CORE: added easy_profiler support

master
Martin Gerhardy 2017-03-02 23:05:17 +01:00
parent dabca6c485
commit 3ce68b904e
89 changed files with 23057 additions and 2 deletions

View File

@ -145,7 +145,7 @@ server client voxedit shapetool worldrenderertool shadertool noisetool databaset
backward flatbuffers glm libenet nativefiledialog restclient-cpp selene zlib lua53 luac libcurl assimp turbobadger sdl2: cmake
$(call COMPILE, $@)
rcon: cmake
rcon profiler: cmake
$(call COMPILE, $@)
$(Q)cd $(BUILDDIR); $(VALGRIND_CMD) $(DEBUG_CMD) $(VOGL_CMD) ./$@ $(ARGS)

View File

@ -1,3 +1,4 @@
add_subdirectory(easy_profiler)
add_subdirectory(backward)
add_subdirectory(glm)
add_subdirectory(zlib)

View File

@ -0,0 +1,154 @@
SET(LIB_NAME "easy_profiler")
file (STRINGS ${CMAKE_CURRENT_LIST_DIR}/version.info EASY_PRODUCT_VERSION_STRING)
string(REPLACE "." ";" VERSION_LIST ${EASY_PRODUCT_VERSION_STRING})
list(GET VERSION_LIST 0 EASY_PROGRAM_VERSION_MAJOR)
list(GET VERSION_LIST 1 EASY_PROGRAM_VERSION_MINOR)
list(GET VERSION_LIST 2 EASY_PROGRAM_VERSION_PATCH)
# EasyProfiler version
add_definitions(
-DEASY_PROFILER_VERSION_MAJOR=${EASY_PROGRAM_VERSION_MAJOR}
-DEASY_PROFILER_VERSION_MINOR=${EASY_PROGRAM_VERSION_MINOR}
-DEASY_PROFILER_VERSION_PATCH=${EASY_PROGRAM_VERSION_PATCH}
)
# EasyProfiler version
set(EASY_PROGRAM_VERSION_MAJOR ${EASY_PROGRAM_VERSION_MAJOR} PARENT_SCOPE)
set(EASY_PROGRAM_VERSION_MINOR ${EASY_PROGRAM_VERSION_MINOR} PARENT_SCOPE)
set(EASY_PROGRAM_VERSION_PATCH ${EASY_PROGRAM_VERSION_PATCH} PARENT_SCOPE)
# EasyProfiler options:----------------------------------------------
set(EASY_DEFAULT_PORT 28077) # Default listening port
set(EASY_OPTION_LISTEN OFF) # Enable automatic startListen on startup
set(EASY_OPTION_PROFILE_SELF OFF) # Enable self profiling (measure time for internal storage expand)
set(EASY_OPTION_PROFILE_SELF_BLOCKS_ON OFF) # Storage expand default status (profiler::ON or profiler::OFF)
set(EASY_OPTION_LOG OFF) # Print errors to stderr
set(EASY_OPTION_PREDEFINED_COLORS ON) # Use predefined set of colors (see profiler_colors.h)
# If you want to use your own colors palette you can turn this option OFF
if(WIN32)
set(EASY_OPTION_EVENT_TRACING ON) # Enable event tracing by default
set(EASY_OPTION_LOW_PRIORITY_EVENT_TRACING ON) # Set low priority for event tracing thread
endif(WIN32)
add_definitions(-DEASY_DEFAULT_PORT=${EASY_DEFAULT_PORT})
if(EASY_OPTION_LISTEN)
add_definitions(-DEASY_OPTION_START_LISTEN_ON_STARTUP=1)
else()
add_definitions(-DEASY_OPTION_START_LISTEN_ON_STARTUP=0)
endif(EASY_OPTION_LISTEN)
if(EASY_OPTION_PROFILE_SELF)
add_definitions(-DEASY_OPTION_MEASURE_STORAGE_EXPAND=1)
if(EASY_OPTION_PROFILE_SELF_BLOCKS_ON)
add_definitions(-DEASY_OPTION_STORAGE_EXPAND_BLOCKS_ON=true)
else()
add_definitions(-DEASY_OPTION_STORAGE_EXPAND_BLOCKS_ON=false)
endif(EASY_OPTION_PROFILE_SELF_BLOCKS_ON)
else()
add_definitions(-DEASY_OPTION_MEASURE_STORAGE_EXPAND=0)
endif(EASY_OPTION_PROFILE_SELF)
if(WIN32)
if(EASY_OPTION_EVENT_TRACING)
add_definitions(-DEASY_OPTION_EVENT_TRACING_ENABLED=true)
else()
add_definitions(-DEASY_OPTION_EVENT_TRACING_ENABLED=false)
endif(EASY_OPTION_EVENT_TRACING)
if(EASY_OPTION_LOW_PRIORITY_EVENT_TRACING)
add_definitions(-DEASY_OPTION_LOW_PRIORITY_EVENT_TRACING=true)
else()
add_definitions(-DEASY_OPTION_LOW_PRIORITY_EVENT_TRACING=false)
endif(EASY_OPTION_LOW_PRIORITY_EVENT_TRACING)
endif(WIN32)
if(EASY_OPTION_LOG)
add_definitions(-DEASY_OPTION_LOG_ENABLED=1)
else()
add_definitions(-DEASY_OPTION_LOG_ENABLED=0)
endif(EASY_OPTION_LOG)
if(EASY_OPTION_PREDEFINED_COLORS)
add_definitions(-DEASY_OPTION_BUILTIN_COLORS=1)
else()
add_definitions(-DEASY_OPTION_BUILTIN_COLORS=0)
endif(EASY_OPTION_PREDEFINED_COLORS)
set(CPP_FILES
block.cpp
profile_manager.cpp
reader.cpp
event_trace_win.cpp
easy_socket.cpp
)
set(H_FILES
profile_manager.h
spin_lock.h
event_trace_win.h
current_time.h
)
include_directories(
include
)
set(INCLUDE_FILES
include/easy/profiler.h
include/easy/reader.h
include/easy/easy_net.h
include/easy/easy_socket.h
include/easy/easy_compiler_support.h
include/easy/profiler_aux.h
include/easy/profiler_colors.h
include/easy/reader.h
include/easy/serialized_block.h
)
source_group(include FILES ${INCLUDE_FILES})
set(SOURCES
${CPP_FILES}
${H_FILES}
${INCLUDE_FILES}
)
add_definitions(
-D_BUILD_PROFILER
-DBUILD_WITH_EASY_PROFILER
#-DEASY_PROFILER_API_DISABLED # uncomment this to disable profiler api only (you will have to rebuild only easy_profiler)
)
if(WIN32)
add_definitions(
-D_WINSOCK_DEPRECATED_NO_WARNINGS
-D_CRT_SECURE_NO_WARNINGS
)
endif(WIN32)
add_library(${LIB_NAME} STATIC ${SOURCES})
if (MINGW)
add_definitions(
-D_WIN32_WINNT=0x0600
-DSTRSAFE_NO_DEPRECATE
)
set (PLATFORM_LIBS ${PLATFORM_LIBS} ws2_32 psapi)
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
elseif (CMAKE_VERSION VERSION_LESS "3.1")
if (UNIX OR CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
set (CMAKE_CXX_FLAGS "-std=gnu++11 ${CMAKE_CXX_FLAGS}")
endif (UNIX OR CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
else ()
set_target_properties(${LIB_NAME} PROPERTIES
CXX_STANDARD 11
CXX_STANDARD_REQUIRED ON
)
endif (MINGW)
if(UNIX)
set(PLATFORM_LIBS ${PLATFORM_LIBS} pthread)
endif(UNIX)
target_link_libraries(${LIB_NAME} ${PLATFORM_LIBS})
target_compile_definitions(${LIB_NAME} PUBLIC BUILD_WITH_EASY_PROFILER)
target_include_directories(${LIB_NAME} PUBLIC include)

View File

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -0,0 +1,628 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.

View File

@ -0,0 +1,155 @@
/************************************************************************
* file name : block.cpp
* ----------------- :
* creation time : 2016/02/16
* authors : Sergey Yagovtsev, Victor Zarubkin
* emails : yse.sey@gmail.com, v.s.zarubkin@gmail.com
* ----------------- :
* description : The file contains implementation of profiling blocks
* :
* license : Lightweight profiler library for c++
* : Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
* :
* :
* : Licensed under the Apache License, Version 2.0 (the "License");
* : you may not use this file except in compliance with the License.
* : You may obtain a copy of the License at
* :
* : http://www.apache.org/licenses/LICENSE-2.0
* :
* : Unless required by applicable law or agreed to in writing, software
* : distributed under the License is distributed on an "AS IS" BASIS,
* : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* : See the License for the specific language governing permissions and
* : limitations under the License.
* :
* :
* : GNU General Public License Usage
* : Alternatively, this file may be used under the terms of the GNU
* : General Public License as published by the Free Software Foundation,
* : either version 3 of the License, or (at your option) any later version.
* :
* : This program is distributed in the hope that it will be useful,
* : but WITHOUT ANY WARRANTY; without even the implied warranty of
* : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
* : GNU General Public License for more details.
* :
* : You should have received a copy of the GNU General Public License
* : along with this program.If not, see <http://www.gnu.org/licenses/>.
************************************************************************/
#include "../easy_profiler/current_time.h"
#include "../easy_profiler/profile_manager.h"
using namespace profiler;
#ifndef EASY_PROFILER_API_DISABLED
BaseBlockData::BaseBlockData(timestamp_t _begin_time, block_id_t _descriptor_id)
: m_begin(_begin_time)
, m_end(0)
, m_id(_descriptor_id)
{
}
Block::Block(Block&& that)
: BaseBlockData(that.m_begin, that.m_id)
, m_name(that.m_name)
, m_status(that.m_status)
{
m_end = that.m_end;
}
Block::Block(timestamp_t _begin_time, block_id_t _descriptor_id, const char* _runtimeName)
: BaseBlockData(_begin_time, _descriptor_id)
, m_name(_runtimeName)
, m_status(::profiler::ON)
{
}
Block::Block(const BaseBlockDescriptor* _descriptor, const char* _runtimeName)
: BaseBlockData(1ULL, _descriptor->id())
, m_name(_runtimeName)
, m_status(_descriptor->status())
{
}
void Block::start()
{
m_begin = getCurrentTime();
}
void Block::start(timestamp_t _time)
{
m_begin = _time;
}
void Block::finish()
{
m_end = getCurrentTime();
}
void Block::finish(timestamp_t _time)
{
m_end = _time;
}
Block::~Block()
{
if (!finished())
::profiler::endBlock();
}
#else
BaseBlockData::BaseBlockData(timestamp_t, block_id_t)
: m_begin(0)
, m_end(0)
, m_id(~0U)
{
}
Block::Block(Block&&)
: BaseBlockData(0, ~0U)
, m_name("")
, m_status(::profiler::OFF)
{
}
Block::Block(timestamp_t, block_id_t, const char*)
: BaseBlockData(0, ~0U)
, m_name("")
, m_status(::profiler::OFF)
{
}
Block::Block(const BaseBlockDescriptor*, const char*)
: BaseBlockData(0, ~0U)
, m_name("")
, m_status(::profiler::OFF)
{
}
void Block::start()
{
}
void Block::start(timestamp_t)
{
}
void Block::finish()
{
}
void Block::finish(timestamp_t)
{
}
Block::~Block()
{
}
#endif

View File

@ -0,0 +1,145 @@
/**
Lightweight profiler library for c++
Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
GNU General Public License Usage
Alternatively, this file may be used under the terms of the GNU
General Public License as published by the Free Software Foundation,
either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program.If not, see <http://www.gnu.org/licenses/>.
**/
#ifndef EASY_______CURRENT_TIME_H_____
#define EASY_______CURRENT_TIME_H_____
#include "../easy_profiler/include/easy/profiler.h"
#ifdef _WIN32
#include <Windows.h>
#else
#include <chrono>
#include <time.h>
#ifdef __ARM_ARCH
#include <sys/time.h>
#endif//__ARM_ARCH
#endif
static inline profiler::timestamp_t getCurrentTime()
{
#ifdef _WIN32
//see https://msdn.microsoft.com/library/windows/desktop/dn553408(v=vs.85).aspx
LARGE_INTEGER elapsedMicroseconds;
if (!QueryPerformanceCounter(&elapsedMicroseconds))
return 0;
return (profiler::timestamp_t)elapsedMicroseconds.QuadPart;
#else// not _WIN32
#if (defined(__GNUC__) || defined(__ICC))
// part of code from google/benchmark library (Licensed under the Apache License, Version 2.0)
// see https://github.com/google/benchmark/blob/master/src/cycleclock.h#L111
#if defined(__i386__)
int64_t ret;
__asm__ volatile("rdtsc" : "=A"(ret));
return ret;
#elif defined(__x86_64__) || defined(__amd64__)
uint64_t low, high;
__asm__ volatile("rdtsc" : "=a"(low), "=d"(high));
return (high << 32) | low;
#elif defined(__powerpc__) || defined(__ppc__)
// This returns a time-base, which is not always precisely a cycle-count.
int64_t tbl, tbu0, tbu1;
asm("mftbu %0" : "=r"(tbu0));
asm("mftb %0" : "=r"(tbl));
asm("mftbu %0" : "=r"(tbu1));
tbl &= -static_cast<int64>(tbu0 == tbu1);
// high 32 bits in tbu1; low 32 bits in tbl (tbu0 is garbage)
return (tbu1 << 32) | tbl;
#elif defined(__sparc__)
int64_t tick;
asm(".byte 0x83, 0x41, 0x00, 0x00");
asm("mov %%g1, %0" : "=r"(tick));
return tick;
#elif defined(__ia64__)
int64_t itc;
asm("mov %0 = ar.itc" : "=r"(itc));
return itc;
#elif defined(COMPILER_MSVC) && defined(_M_IX86)
// Older MSVC compilers (like 7.x) don't seem to support the
// __rdtsc intrinsic properly, so I prefer to use _asm instead
// when I know it will work. Otherwise, I'll use __rdtsc and hope
// the code is being compiled with a non-ancient compiler.
_asm rdtsc
#elif defined(COMPILER_MSVC)
return __rdtsc();
#elif defined(__aarch64__)
// System timer of ARMv8 runs at a different frequency than the CPU's.
// The frequency is fixed, typically in the range 1-50MHz. It can be
// read at CNTFRQ special register. We assume the OS has set up
// the virtual timer properly.
int64_t virtual_timer_value;
asm volatile("mrs %0, cntvct_el0" : "=r"(virtual_timer_value));
return virtual_timer_value;
#elif defined(__ARM_ARCH)
#if (__ARM_ARCH >= 6) // V6 is the earliest arch that has a standard cyclecount
uint32_t pmccntr;
uint32_t pmuseren;
uint32_t pmcntenset;
// Read the user mode perf monitor counter access permissions.
asm volatile("mrc p15, 0, %0, c9, c14, 0" : "=r"(pmuseren));
if (pmuseren & 1) { // Allows reading perfmon counters for user mode code.
asm volatile("mrc p15, 0, %0, c9, c12, 1" : "=r"(pmcntenset));
if (pmcntenset & 0x80000000ul) { // Is it counting?
asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r"(pmccntr));
// The counter is set up to count every 64th cycle
return static_cast<int64_t>(pmccntr) * 64; // Should optimize to << 6
}
}
#endif
struct timeval tv;
gettimeofday(&tv, nullptr);
return static_cast<int64_t>(tv.tv_sec) * 1000000 + tv.tv_usec;
#elif defined(__mips__)
// mips apparently only allows rdtsc for superusers, so we fall
// back to gettimeofday. It's possible clock_gettime would be better.
struct timeval tv;
gettimeofday(&tv, nullptr);
return static_cast<int64_t>(tv.tv_sec) * 1000000 + tv.tv_usec;
#else
#warning You need to define fast getCurrentTime() for your OS and CPU
return std::chrono::time_point_cast<std::chrono::nanoseconds>(std::chrono::system_clock::now()).time_since_epoch().count();
#define USE_STD_CHRONO
#endif
#else // not _WIN32, __GNUC__, __ICC
#warning You need to define fast getCurrentTime() for your OS and CPU
return std::chrono::time_point_cast<std::chrono::nanoseconds>(std::chrono::system_clock::now()).time_since_epoch().count();
#define USE_STD_CHRONO
#endif
#endif
}
#endif // EASY_______CURRENT_TIME_H_____

View File

@ -0,0 +1,336 @@
/**
Lightweight profiler library for c++
Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
GNU General Public License Usage
Alternatively, this file may be used under the terms of the GNU
General Public License as published by the Free Software Foundation,
either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program.If not, see <http://www.gnu.org/licenses/>.
**/
#include "../easy_profiler/include/easy/easy_socket.h"
#include <string.h>
#include <thread>
#ifdef _WIN32
#pragma comment (lib, "Ws2_32.lib")
#pragma comment (lib, "Mswsock.lib")
#pragma comment (lib, "AdvApi32.lib")
#else
#include <errno.h>
#include <sys/ioctl.h>
#endif
bool EasySocket::checkSocket(socket_t s) const
{
return s > 0;
}
int EasySocket::_close(EasySocket::socket_t s)
{
#ifdef _WIN32
return ::closesocket(s);
#else
//TODO
//return close(s);
return 0;
#endif
}
void EasySocket::setBlocking(EasySocket::socket_t s, bool blocking)
{
#ifdef _WIN32
u_long iMode = blocking ? 0 : 1;//0 - blocking, 1 - non blocking
ioctlsocket(s, FIONBIO, &iMode);
#else
const int iMode = blocking ? 0 : 1;//0 - blocking, 1 - non blocking
ioctl(s, FIONBIO, (char *)&iMode);
#endif
}
int EasySocket::bind(uint16_t portno)
{
if (!checkSocket(m_socket)) return -1;
struct sockaddr_in serv_addr;
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
auto res = ::bind(m_socket, (struct sockaddr *) &serv_addr, sizeof(serv_addr));
return res;
}
void EasySocket::flush()
{
if (m_socket){
_close(m_socket);
}
if (m_replySocket != m_socket){
_close(m_replySocket);
}
#ifdef _WIN32
m_socket = 0;
m_replySocket = 0;
#else
wsaret = 0;
#endif
}
void EasySocket::checkResult(int result)
{
//printf("Errno: %s\n", strerror(errno));
if(result >= 0){
m_state = CONNECTION_STATE_SUCCESS;
return;
}else if(result == -1){
int error_code = 0;
#ifdef _WIN32
error_code = WSAGetLastError();
const int CONNECTION_ABORTED = WSAECONNABORTED;
const int CONNECTION_RESET = WSAECONNRESET;
const int CONNECTION_IN_PROGRESS = WSAEINPROGRESS;
#else
error_code = errno;
const int CONNECTION_ABORTED = ECONNABORTED;
const int CONNECTION_RESET = ECONNRESET;
const int CONNECTION_IN_PROGRESS = EINPROGRESS;
const int CONNECTION_BROKEN_PIPE = EPIPE;
const int CONNECTION_ENOENT = ENOENT;
#endif
switch(error_code)
{
case CONNECTION_ABORTED:
case CONNECTION_RESET:
#ifndef _WIN32
case CONNECTION_BROKEN_PIPE:
case CONNECTION_ENOENT:
#endif
m_state = CONNECTION_STATE_DISCONNECTED;
break;
case CONNECTION_IN_PROGRESS:
m_state = CONNECTION_STATE_IN_PROGRESS;
break;
default:
break;
}
}
}
void EasySocket::init()
{
if (wsaret == 0)
{
int protocol = 0;
#ifdef _WIN32
protocol = IPPROTO_TCP;
#endif
m_socket = socket(AF_INET, SOCK_STREAM, protocol);
if (!checkSocket(m_socket)) {
return;
}
}else
return;
setBlocking(m_socket,true);
#ifndef _WIN32
wsaret = 1;
#endif
int opt = 1;
setsockopt(m_socket, SOL_SOCKET, SO_REUSEADDR, (const char *)&opt, sizeof(opt));
}
EasySocket::EasySocket()
{
#ifdef _WIN32
WSADATA wsaData;
wsaret = WSAStartup(0x101, &wsaData);
#else
wsaret = 0;
#endif
init();
#ifndef _WIN32
wsaret = 1;
#endif
}
EasySocket::~EasySocket()
{
flush();
#ifdef _WIN32
if (wsaret == 0)
WSACleanup();
#endif
}
int EasySocket::send(const void *buf, size_t nbyte)
{
if(!checkSocket(m_replySocket)) return -1;
int res = 0;
#ifdef _WIN32
res = ::send(m_replySocket, (const char*)buf, (int)nbyte, 0);
#else
res = ::send(m_replySocket,buf,nbyte,MSG_NOSIGNAL);
#endif
checkResult(res);
return res;
}
int EasySocket::receive(void *buf, size_t nbyte)
{
if(!checkSocket(m_replySocket)) return -1;
int res = 0;
#ifdef _WIN32
res = ::recv(m_replySocket, (char*)buf, (int)nbyte, 0);
#else
res = ::read(m_replySocket,buf,nbyte);
#endif
checkResult(res);
if (res == 0){
m_state = CONNECTION_STATE_DISCONNECTED;
}
return res;
}
int EasySocket::listen(int count)
{
if(!checkSocket(m_socket)) return -1;
int res = ::listen(m_socket,count);
checkResult(res);
return res;
}
int EasySocket::accept()
{
if(!checkSocket(m_socket)) return -1;
fd_set fdread, fdwrite, fdexcl;
timeval tv = { 0 };
FD_ZERO (&fdread);
FD_SET (m_socket, &fdread);
fdwrite = fdread;
fdexcl = fdread;
tv.tv_sec = 0; tv.tv_usec = 500;
int rc =select (m_socket+1, &fdread, &fdwrite, &fdexcl, &tv);
if(rc <= 0){
//there is no connection for accept
return -1;
}
m_replySocket = ::accept(m_socket,nullptr,nullptr);
checkResult((int)m_replySocket);
if(checkSocket(m_replySocket))
{
int send_buffer = 64*1024*1024;
int send_buffer_sizeof = sizeof(int);
setsockopt(m_replySocket, SOL_SOCKET, SO_SNDBUF, (char*)&send_buffer, send_buffer_sizeof);
//int flag = 1;
//int result = setsockopt(m_replySocket,IPPROTO_TCP,TCP_NODELAY,(char *)&flag,sizeof(int));
//setBlocking(m_replySocket,true);
}
return (int)m_replySocket;
}
bool EasySocket::setAddress(const char *serv, uint16_t portno)
{
server = gethostbyname(serv);
if (server == NULL) {
return false;
//fprintf(stderr,"ERROR, no such host\n");
}
memset((char *)&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
memcpy((char *)&serv_addr.sin_addr.s_addr, (char *)server->h_addr, server->h_length);
serv_addr.sin_port = htons(portno);
return true;
}
int EasySocket::connect()
{
if (server == NULL || m_socket <=0 ) {
return -1;
//fprintf(stderr,"ERROR, no such host\n");
}
int res = 0;
//TODO: more intelligence
#ifndef _WIN32
setBlocking(m_socket,false);
int counter = 0;
int sleepMs = 20;
int waitSec = 1;
int waitMs = waitSec*1000/sleepMs;
while(counter++ < waitMs)
{
res = ::connect(m_socket,(struct sockaddr *) &serv_addr,sizeof(serv_addr));
checkResult(res);
if (res == 0)
break;
if (m_state == CONNECTION_STATE_IN_PROGRESS)
{
std::this_thread::sleep_for(std::chrono::milliseconds(sleepMs));
continue;
}
if(m_state != CONNECTION_STATE_IN_PROGRESS && m_state != CONNECTION_STATE_SUCCESS )
break;
}
setBlocking(m_socket,true);
#else
res = ::connect(m_socket, (struct sockaddr *) &serv_addr, sizeof(serv_addr));
checkResult(res);
#endif
if(res == 0){
struct timeval tv;
tv.tv_sec = 1;
tv.tv_usec = 0;
setsockopt(m_socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv,sizeof(struct timeval));
m_replySocket = m_socket;
}
return res;
}

View File

@ -0,0 +1,27 @@
#ifndef EASY_PROFILER__EVENT_TRACE_STATUS__H_
#define EASY_PROFILER__EVENT_TRACE_STATUS__H_
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
namespace profiler {
enum EventTracingEnableStatus : unsigned char
{
EVENT_TRACING_LAUNCHED_SUCCESSFULLY = 0,
EVENT_TRACING_NOT_ENOUGH_ACCESS_RIGHTS,
EVENT_TRACING_WAS_LAUNCHED_BY_SOMEBODY_ELSE,
EVENT_TRACING_BAD_PROPERTIES_SIZE,
EVENT_TRACING_OPEN_TRACE_ERROR,
EVENT_TRACING_MISTERIOUS_ERROR,
};
} // END of namespace profiler.
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
#endif // EASY_PROFILER__EVENT_TRACE_STATUS__H_

View File

@ -0,0 +1,530 @@
/************************************************************************
* file name : event_trace_win.cpp
* ----------------- :
* creation time : 2016/09/04
* author : Victor Zarubkin
* email : v.s.zarubkin@gmail.com
* ----------------- :
* description : The file contains implementation of EasyEventTracer class used for tracing
* : Windows system events to get context switches.
* ----------------- :
* change log : * 2016/09/04 Victor Zarubkin: initial commit.
* :
* : * 2016/09/13 Victor Zarubkin: get process id and process name
* : of the owner of thread with id == CSwitch::NewThreadId.
* :
* : * 2016/09/17 Victor Zarubkin: added log messages printing.
* ----------------- :
* license : Lightweight profiler library for c++
* : Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
* :
* :
* : Licensed under the Apache License, Version 2.0 (the "License");
* : you may not use this file except in compliance with the License.
* : You may obtain a copy of the License at
* :
* : http://www.apache.org/licenses/LICENSE-2.0
* :
* : Unless required by applicable law or agreed to in writing, software
* : distributed under the License is distributed on an "AS IS" BASIS,
* : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* : See the License for the specific language governing permissions and
* : limitations under the License.
* :
* :
* : GNU General Public License Usage
* : Alternatively, this file may be used under the terms of the GNU
* : General Public License as published by the Free Software Foundation,
* : either version 3 of the License, or (at your option) any later version.
* :
* : This program is distributed in the hope that it will be useful,
* : but WITHOUT ANY WARRANTY; without even the implied warranty of
* : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
* : GNU General Public License for more details.
* :
* : You should have received a copy of the GNU General Public License
* : along with this program.If not, see <http://www.gnu.org/licenses/>.
************************************************************************/
#ifdef _WIN32
#include <memory.h>
#include <chrono>
#include <unordered_map>
#include "easy/profiler.h"
#include "profile_manager.h"
#include "current_time.h"
#include "event_trace_win.h"
#include <Psapi.h>
#include <processthreadsapi.h>
//#include <Shellapi.h>
#if EASY_OPTION_LOG_ENABLED != 0
# include <iostream>
# ifndef EASY_ERRORLOG
# define EASY_ERRORLOG ::std::cerr
# endif
# ifndef EASY_LOG
# define EASY_LOG ::std::cerr
# endif
# ifndef EASY_ERROR
# define EASY_ERROR(LOG_MSG) EASY_ERRORLOG << "EasyProfiler ERROR: " << LOG_MSG
# endif
# ifndef EASY_WARNING
# define EASY_WARNING(LOG_MSG) EASY_ERRORLOG << "EasyProfiler WARNING: " << LOG_MSG
# endif
# ifndef EASY_LOGMSG
# define EASY_LOGMSG(LOG_MSG) EASY_LOG << "EasyProfiler INFO: " << LOG_MSG
# endif
# ifndef EASY_LOG_ONLY
# define EASY_LOG_ONLY(CODE) CODE
# endif
#else
# ifndef EASY_ERROR
# define EASY_ERROR(LOG_MSG)
# endif
# ifndef EASY_WARNING
# define EASY_WARNING(LOG_MSG)
# endif
# ifndef EASY_LOGMSG
# define EASY_LOGMSG(LOG_MSG)
# endif
# ifndef EASY_LOG_ONLY
# define EASY_LOG_ONLY(CODE)
# endif
#endif
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//extern ProfileManager& MANAGER;
#define MANAGER ProfileManager::instance()
extern const ::profiler::color_t EASY_COLOR_INTERNAL_EVENT;
#ifdef __MINGW32__
::std::atomic<uint64_t> TRACING_END_TIME = ATOMIC_VAR_INIT(~0ULL);
char KERNEL_LOGGER[] = KERNEL_LOGGER_NAME;
#else
::std::atomic_uint64_t TRACING_END_TIME = ATOMIC_VAR_INIT(~0ULL);
#endif
namespace profiler {
const decltype(EVENT_DESCRIPTOR::Opcode) SWITCH_CONTEXT_OPCODE = 36;
const int RAW_TIMESTAMP_TIME_TYPE = 1;
//////////////////////////////////////////////////////////////////////////
struct ProcessInfo {
std::string name;
processid_t id = 0;
int8_t valid = 0;
};
//////////////////////////////////////////////////////////////////////////
// CSwitch class
// See https://msdn.microsoft.com/en-us/library/windows/desktop/aa964744(v=vs.85).aspx
// EventType = 36
struct CSwitch
{
uint32_t NewThreadId;
uint32_t OldThreadId;
int8_t NewThreadPriority;
int8_t OldThreadPriority;
uint8_t PreviousCState;
int8_t SpareByte;
int8_t OldThreadWaitReason;
int8_t OldThreadWaitMode;
int8_t OldThreadState;
int8_t OldThreadWaitIdealProcessor;
uint32_t NewThreadWaitTime;
uint32_t Reserved;
};
//////////////////////////////////////////////////////////////////////////
typedef ::std::unordered_map<decltype(CSwitch::NewThreadId), ProcessInfo*, ::profiler::do_not_calc_hash> thread_process_info_map;
typedef ::std::unordered_map<processid_t, ProcessInfo, ::profiler::do_not_calc_hash> process_info_map;
// Using static is safe because processTraceEvent() is called from one thread
process_info_map PROCESS_INFO_TABLE;
thread_process_info_map THREAD_PROCESS_INFO_TABLE = ([](){ thread_process_info_map initial; initial[0U] = nullptr; return ::std::move(initial); })();
//////////////////////////////////////////////////////////////////////////
void WINAPI processTraceEvent(PEVENT_RECORD _traceEvent)
{
if (_traceEvent->EventHeader.EventDescriptor.Opcode != SWITCH_CONTEXT_OPCODE)
return;
if (sizeof(CSwitch) != _traceEvent->UserDataLength)
return;
EASY_FUNCTION(EASY_COLOR_INTERNAL_EVENT, ::profiler::OFF);
auto _contextSwitchEvent = reinterpret_cast<CSwitch*>(_traceEvent->UserData);
const auto time = static_cast<::profiler::timestamp_t>(_traceEvent->EventHeader.TimeStamp.QuadPart);
if (time > TRACING_END_TIME.load(::std::memory_order_acquire))
return;
processid_t pid = 0;
const char* process_name = "";
// Trying to get target process name and id
auto it = THREAD_PROCESS_INFO_TABLE.find(_contextSwitchEvent->NewThreadId);
if (it == THREAD_PROCESS_INFO_TABLE.end())
{
auto hThread = OpenThread(THREAD_QUERY_LIMITED_INFORMATION, FALSE, _contextSwitchEvent->NewThreadId);
if (hThread != nullptr)
{
pid = GetProcessIdOfThread(hThread);
auto pinfo = &PROCESS_INFO_TABLE[pid];
if (pinfo->valid == 0)
{
if (pinfo->name.empty())
{
static char numbuf[128] = {};
sprintf(numbuf, "%u", pid);
pinfo->name = numbuf;
pinfo->id = pid;
}
/*
According to documentation, using GetModuleBaseName() requires
PROCESS_QUERY_INFORMATION | PROCESS_VM_READ access rights.
But it works fine with PROCESS_QUERY_LIMITED_INFORMATION instead of PROCESS_QUERY_INFORMATION.
See https://msdn.microsoft.com/en-us/library/windows/desktop/ms683196(v=vs.85).aspx
*/
//auto hProc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
//if (hProc == nullptr)
auto hProc = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_VM_READ, FALSE, pid);
if (hProc != nullptr)
{
static TCHAR buf[MAX_PATH] = {}; // Using static is safe because processTraceEvent() is called from one thread
auto len = GetModuleBaseName(hProc, 0, buf, MAX_PATH);
if (len != 0)
{
pinfo->name.reserve(pinfo->name.size() + 2 + len);
pinfo->name.append(" ", 1);
pinfo->name.append(buf, len);
pinfo->valid = 1;
}
CloseHandle(hProc);
}
else
{
//auto err = GetLastError();
//printf("OpenProcess(%u) fail: GetLastError() == %u\n", pid, err);
pinfo->valid = -1;
if (pid == 4) {
pinfo->name.reserve(pinfo->name.size() + 8);
pinfo->name.append(" System", 7);
}
}
}
process_name = pinfo->name.c_str();
THREAD_PROCESS_INFO_TABLE[_contextSwitchEvent->NewThreadId] = pinfo;
CloseHandle(hThread);
}
else
{
//printf("Can not OpenThread(%u);\n", _contextSwitchEvent->NewThreadId);
THREAD_PROCESS_INFO_TABLE[_contextSwitchEvent->NewThreadId] = nullptr;
}
}
else
{
auto pinfo = it->second;
if (pinfo != nullptr)
process_name = pinfo->name.c_str();
else if (it->first == 0)
process_name = "System Idle";
else if (it->first == 4)
process_name = "System";
}
MANAGER.beginContextSwitch(_contextSwitchEvent->OldThreadId, time, _contextSwitchEvent->NewThreadId, process_name);
MANAGER.endContextSwitch(_contextSwitchEvent->NewThreadId, pid, time);
}
//////////////////////////////////////////////////////////////////////////
#ifndef EASY_MAGIC_STATIC_CPP11
class EasyEventTracerInstance {
friend EasyEventTracer;
EasyEventTracer instance;
} EASY_EVENT_TRACER;
#endif
EasyEventTracer& EasyEventTracer::instance()
{
#ifndef EASY_MAGIC_STATIC_CPP11
return EASY_EVENT_TRACER.instance;
#else
static EasyEventTracer tracer;
return tracer;
#endif
}
EasyEventTracer::EasyEventTracer()
{
m_lowPriority = ATOMIC_VAR_INIT(EASY_OPTION_LOW_PRIORITY_EVENT_TRACING);
}
EasyEventTracer::~EasyEventTracer()
{
disable();
}
bool EasyEventTracer::isLowPriority() const
{
return m_lowPriority.load(::std::memory_order_acquire);
}
void EasyEventTracer::setLowPriority(bool _value)
{
m_lowPriority.store(_value, ::std::memory_order_release);
}
bool setPrivilege(HANDLE hToken, LPCSTR _privelegeName)
{
bool success = false;
if (hToken)
{
LUID privilegyId;
if (LookupPrivilegeValue(NULL, _privelegeName, &privilegyId))
{
TOKEN_PRIVILEGES tokenPrivilege;
tokenPrivilege.PrivilegeCount = 1;
tokenPrivilege.Privileges[0].Luid = privilegyId;
tokenPrivilege.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
success = AdjustTokenPrivileges(hToken, FALSE, &tokenPrivilege, sizeof(TOKEN_PRIVILEGES), NULL, NULL) != FALSE;
}
}
EASY_LOG_ONLY(
if (!success)
EASY_WARNING("Failed to set " << _privelegeName << " privelege for the application.\n");
)
return success;
}
void EasyEventTracer::setProcessPrivileges()
{
static bool alreadySet = false;
if (alreadySet)
return;
alreadySet = true;
HANDLE hToken = nullptr;
if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
{
#if EASY_OPTION_LOG_ENABLED != 0
const bool success = setPrivilege(hToken, SE_DEBUG_NAME);
if (!success)
EASY_WARNING("Some context switch events could not get process name.\n");
#else
setPrivilege(hToken, SE_DEBUG_NAME);
#endif
CloseHandle(hToken);
}
EASY_LOG_ONLY(
else {
EASY_WARNING("Failed to open process to adjust priveleges.\n");
}
)
}
::profiler::EventTracingEnableStatus EasyEventTracer::startTrace(bool _force, int _step)
{
auto startTraceResult = StartTrace(&m_sessionHandle, KERNEL_LOGGER_NAME, props());
switch (startTraceResult)
{
case ERROR_SUCCESS:
return EVENT_TRACING_LAUNCHED_SUCCESSFULLY;
case ERROR_ALREADY_EXISTS:
{
if (_force)
{
// Try to stop another event tracing session to force launch self session.
if (_step == 0)
{
/*
According to https://msdn.microsoft.com/en-us/library/windows/desktop/aa363696(v=vs.85).aspx
SessionHandle is ignored (and could be NULL) if SessionName is not NULL,
and you only need to set the Wnode.BufferSize, Wnode.Guid, LoggerNameOffset, and LogFileNameOffset
in EVENT_TRACE_PROPERTIES structure if ControlCode is EVENT_TRACE_CONTROL_STOP.
All data is already set for m_properties to the moment. Simply copy m_properties and use the copy.
This method supposed to be faster than launching console window and executing shell command,
but if that would not work, return to using shell command "logman stop".
*/
// static is safe because we are guarded by spin-lock m_spin
static Properties p = ([]{ Properties prp; strncpy(prp.sessionName, KERNEL_LOGGER_NAME, sizeof(prp.sessionName)); return prp; })();
p.base = m_properties.base; // Use copy of m_properties to make sure m_properties will not be changed
// Stop another session
ControlTrace(NULL, KERNEL_LOGGER_NAME, reinterpret_cast<EVENT_TRACE_PROPERTIES*>(&p), EVENT_TRACE_CONTROL_STOP);
// Console window variant:
//if (32 >= (int)ShellExecute(NULL, NULL, "logman", "stop \"" KERNEL_LOGGER_NAME "\" -ets", NULL, SW_HIDE))
// return EVENT_TRACING_WAS_LAUNCHED_BY_SOMEBODY_ELSE;
}
if (_step < 4)
{
// Command executed successfully. Wait for a few time until tracing session finish.
::std::this_thread::sleep_for(::std::chrono::milliseconds(500));
return startTrace(true, ++_step);
}
}
EASY_ERROR("Event tracing not launched: ERROR_ALREADY_EXISTS. To stop another session execute cmd: logman stop \"" << KERNEL_LOGGER_NAME << "\" -ets\n");
return EVENT_TRACING_WAS_LAUNCHED_BY_SOMEBODY_ELSE;
}
case ERROR_ACCESS_DENIED:
EASY_ERROR("Event tracing not launched: ERROR_ACCESS_DENIED. Try to launch your application as Administrator.\n");
return EVENT_TRACING_NOT_ENOUGH_ACCESS_RIGHTS;
case ERROR_BAD_LENGTH:
EASY_ERROR("Event tracing not launched: ERROR_BAD_LENGTH. It seems that your KERNEL_LOGGER_NAME differs from \"" << m_properties.sessionName << "\". Try to re-compile easy_profiler or contact EasyProfiler developers.\n");
return EVENT_TRACING_BAD_PROPERTIES_SIZE;
}
EASY_ERROR("Event tracing not launched: StartTrace() returned " << startTraceResult << ::std::endl);
return EVENT_TRACING_MISTERIOUS_ERROR;
}
::profiler::EventTracingEnableStatus EasyEventTracer::enable(bool _force)
{
::profiler::guard_lock<::profiler::spin_lock> lock(m_spin);
if (m_bEnabled)
return EVENT_TRACING_LAUNCHED_SUCCESSFULLY;
/*
Trying to set debug privilege for current process
to be able to get other process information (process name).
*/
EasyEventTracer::setProcessPrivileges();
// Clear properties
memset(&m_properties, 0, sizeof(m_properties));
m_properties.base.Wnode.BufferSize = sizeof(m_properties);
m_properties.base.Wnode.Flags = WNODE_FLAG_TRACED_GUID;
m_properties.base.Wnode.ClientContext = RAW_TIMESTAMP_TIME_TYPE;
m_properties.base.Wnode.Guid = SystemTraceControlGuid;
m_properties.base.LoggerNameOffset = sizeof(m_properties.base);
m_properties.base.EnableFlags = EVENT_TRACE_FLAG_CSWITCH;
m_properties.base.LogFileMode = EVENT_TRACE_REAL_TIME_MODE;
// Start event tracing
auto res = startTrace(_force);
if (res != EVENT_TRACING_LAUNCHED_SUCCESSFULLY)
return res;
memset(&m_trace, 0, sizeof(m_trace));
#ifdef __MINGW32__
m_trace.LoggerName = KERNEL_LOGGER;
#else
m_trace.LoggerName = KERNEL_LOGGER_NAME;
#endif
m_trace.ProcessTraceMode = PROCESS_TRACE_MODE_REAL_TIME | PROCESS_TRACE_MODE_EVENT_RECORD | PROCESS_TRACE_MODE_RAW_TIMESTAMP;
m_trace.EventRecordCallback = ::profiler::processTraceEvent;
m_openedHandle = OpenTrace(&m_trace);
if (m_openedHandle == INVALID_PROCESSTRACE_HANDLE)
{
EASY_ERROR("Event tracing not launched: OpenTrace() returned invalid handle.\n");
return EVENT_TRACING_OPEN_TRACE_ERROR;
}
/*
Have to launch a thread to process events because according to MSDN documentation:
The ProcessTrace function blocks the thread until it delivers all events, the BufferCallback function returns FALSE,
or you call CloseTrace. If the consumer is consuming events in real time, the ProcessTrace function returns after
the controller stops the trace session. (Note that there may be a several-second delay before the function returns.)
https://msdn.microsoft.com/en-us/library/windows/desktop/aa364093(v=vs.85).aspx
*/
m_processThread = ::std::thread([this](bool _lowPriority)
{
if (_lowPriority) // Set low priority for event tracing thread
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_LOWEST);
EASY_THREAD_SCOPE("EasyProfiler.ETW");
ProcessTrace(&m_openedHandle, 1, 0, 0);
}, m_lowPriority.load(::std::memory_order_acquire));
m_bEnabled = true;
EASY_LOGMSG("Event tracing launched\n");
return EVENT_TRACING_LAUNCHED_SUCCESSFULLY;
}
void EasyEventTracer::disable()
{
::profiler::guard_lock<::profiler::spin_lock> lock(m_spin);
if (!m_bEnabled)
return;
EASY_LOGMSG("Event tracing is stopping...\n");
TRACING_END_TIME.store(getCurrentTime(), ::std::memory_order_release);
ControlTrace(m_openedHandle, KERNEL_LOGGER_NAME, props(), EVENT_TRACE_CONTROL_STOP);
CloseTrace(m_openedHandle);
// Wait for ProcessTrace to finish to make sure no processTraceEvent() will be called later.
if (m_processThread.joinable())
m_processThread.join();
m_bEnabled = false;
// processTraceEvent() is not called anymore. Clean static maps is safe.
PROCESS_INFO_TABLE.clear();
THREAD_PROCESS_INFO_TABLE.clear();
THREAD_PROCESS_INFO_TABLE[0U] = nullptr;
TRACING_END_TIME.store(~0ULL, ::std::memory_order_release);
EASY_LOGMSG("Event tracing stopped\n");
}
} // END of namespace profiler.
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
#endif // _WIN32

View File

@ -0,0 +1,120 @@
/************************************************************************
* file name : event_trace_win.h
* ----------------- :
* creation time : 2016/09/04
* author : Victor Zarubkin
* email : v.s.zarubkin@gmail.com
* ----------------- :
* description : The file contains declaration of EasyEventTracer class used for tracing
* : Windows system events to get context switches.
* ----------------- :
* change log : * 2016/09/04 Victor Zarubkin: initial commit.
* :
* : *
* ----------------- :
* license : Lightweight profiler library for c++
* : Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
* :
* :
* : Licensed under the Apache License, Version 2.0 (the "License");
* : you may not use this file except in compliance with the License.
* : You may obtain a copy of the License at
* :
* : http://www.apache.org/licenses/LICENSE-2.0
* :
* : Unless required by applicable law or agreed to in writing, software
* : distributed under the License is distributed on an "AS IS" BASIS,
* : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* : See the License for the specific language governing permissions and
* : limitations under the License.
* :
* :
* : GNU General Public License Usage
* : Alternatively, this file may be used under the terms of the GNU
* : General Public License as published by the Free Software Foundation,
* : either version 3 of the License, or (at your option) any later version.
* :
* : This program is distributed in the hope that it will be useful,
* : but WITHOUT ANY WARRANTY; without even the implied warranty of
* : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
* : GNU General Public License for more details.
* :
* : You should have received a copy of the GNU General Public License
* : along with this program.If not, see <http://www.gnu.org/licenses/>.
************************************************************************/
#ifndef EASY_PROFILER__EVENT_TRACE_WINDOWS__H_
#define EASY_PROFILER__EVENT_TRACE_WINDOWS__H_
#ifdef _WIN32
#define INITGUID // This is to enable using SystemTraceControlGuid in evntrace.h.
#include <Windows.h>
#include <Strsafe.h>
#include <wmistr.h>
#include <evntrace.h>
#include <evntcons.h>
#include <thread>
#include <atomic>
#include "../easy_profiler/event_trace_status.h"
#include "../easy_profiler/spin_lock.h"
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
namespace profiler {
class EasyEventTracer EASY_FINAL
{
#ifndef EASY_MAGIC_STATIC_CPP11
friend class EasyEventTracerInstance;
#endif
#pragma pack(push, 1)
struct Properties {
EVENT_TRACE_PROPERTIES base;
char sessionName[sizeof(KERNEL_LOGGER_NAME)];
};
#pragma pack(pop)
::std::thread m_processThread;
Properties m_properties;
EVENT_TRACE_LOGFILE m_trace;
::profiler::spin_lock m_spin;
::std::atomic_bool m_lowPriority;
TRACEHANDLE m_sessionHandle = INVALID_PROCESSTRACE_HANDLE;
TRACEHANDLE m_openedHandle = INVALID_PROCESSTRACE_HANDLE;
bool m_bEnabled = false;
public:
static EasyEventTracer& instance();
~EasyEventTracer();
bool isLowPriority() const;
::profiler::EventTracingEnableStatus enable(bool _force = false);
void disable();
void setLowPriority(bool _value);
static void setProcessPrivileges();
private:
EasyEventTracer();
inline EVENT_TRACE_PROPERTIES* props()
{
return reinterpret_cast<EVENT_TRACE_PROPERTIES*>(&m_properties);
}
::profiler::EventTracingEnableStatus startTrace(bool _force, int _step = 0);
}; // END of class EasyEventTracer.
} // END of namespace profiler.
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
#endif // _WIN32
#endif // EASY_PROFILER__EVENT_TRACE_WINDOWS__H_

View File

@ -0,0 +1,274 @@
/************************************************************************
* file name : hashed_str.h
* ----------------- :
* creation time : 2016/09/11
* author : Victor Zarubkin
* email : v.s.zarubkin@gmail.com
* ----------------- :
* description : The file contains definition of C-strings with calculated hash-code.
* : These strings may be used as optimized keys for std::unordered_map.
* ----------------- :
* change log : * 2016/09/11 Victor Zarubkin: Initial commit. Moved sources from reader.cpp
* :
* : *
* ----------------- :
* license : Lightweight profiler library for c++
* : Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
* :
* : This program is free software : you can redistribute it and / or modify
* : it under the terms of the GNU General Public License as published by
* : the Free Software Foundation, either version 3 of the License, or
* : (at your option) any later version.
* :
* : This program is distributed in the hope that it will be useful,
* : but WITHOUT ANY WARRANTY; without even the implied warranty of
* : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
* : GNU General Public License for more details.
* :
* : You should have received a copy of the GNU General Public License
* : along with this program.If not, see <http://www.gnu.org/licenses/>.
************************************************************************/
#ifndef EASY_PROFILER__HASHED_CSTR__H_
#define EASY_PROFILER__HASHED_CSTR__H_
#include <functional>
#include <string.h>
#include <string>
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
#if defined(_MSC_VER)// && _MSC_VER >= 1800
# define EASY_PROFILER_HASHED_CSTR_DEFINED
namespace profiler {
/** \brief Simple C-string pointer with length.
It is used as base class for a key in std::unordered_map.
It is used to get better performance than std::string.
It simply stores a pointer and a length, there is no
any memory allocation and copy.
\warning Make sure you know what you are doing. You have to be sure that
pointed C-string will exist until you finish using this cstring.
\ingroup profiler
*/
class cstring
{
protected:
const char* m_str;
size_t m_len;
public:
cstring(const char* _str) : m_str(_str), m_len(strlen(_str))
{
}
cstring(const char* _str, size_t _len) : m_str(_str), m_len(_len)
{
}
cstring(const cstring&) = default;
cstring& operator = (const cstring&) = default;
inline bool operator == (const cstring& _other) const
{
return m_len == _other.m_len && !strncmp(m_str, _other.m_str, m_len);
}
inline bool operator != (const cstring& _other) const
{
return !operator == (_other);
}
inline bool operator < (const cstring& _other) const
{
if (m_len == _other.m_len)
{
return strncmp(m_str, _other.m_str, m_len) < 0;
}
return m_len < _other.m_len;
}
inline const char* c_str() const
{
return m_str;
}
inline size_t size() const
{
return m_len;
}
}; // END of class cstring.
/** \brief cstring with precalculated hash.
This is used to calculate hash for C-string and to cache it
to be used in the future without recurring hash calculatoin.
\note This class is used as a key in std::unordered_map.
\ingroup profiler
*/
class hashed_cstr : public cstring
{
typedef cstring Parent;
size_t m_hash;
public:
hashed_cstr(const char* _str) : Parent(_str), m_hash(0)
{
m_hash = ::std::_Hash_seq((const unsigned char *)m_str, m_len);
}
hashed_cstr(const char* _str, size_t _hash_code) : Parent(_str), m_hash(_hash_code)
{
}
hashed_cstr(const char* _str, size_t _len, size_t _hash_code) : Parent(_str, _len), m_hash(_hash_code)
{
}
hashed_cstr(const hashed_cstr&) = default;
hashed_cstr& operator = (const hashed_cstr&) = default;
inline bool operator == (const hashed_cstr& _other) const
{
return m_hash == _other.m_hash && Parent::operator == (_other);
}
inline bool operator != (const hashed_cstr& _other) const
{
return !operator == (_other);
}
inline size_t hcode() const
{
return m_hash;
}
}; // END of class hashed_cstr.
} // END of namespace profiler.
namespace std {
/** \brief Simply returns precalculated hash of a C-string. */
template <> struct hash<::profiler::hashed_cstr> {
typedef ::profiler::hashed_cstr argument_type;
typedef size_t result_type;
inline size_t operator () (const ::profiler::hashed_cstr& _str) const {
return _str.hcode();
}
};
} // END of namespace std.
#else ////////////////////////////////////////////////////////////////////
// TODO: Create hashed_cstr for Linux (need to use Linux version of std::_Hash_seq)
#endif
namespace profiler {
class hashed_stdstring
{
::std::string m_str;
size_t m_hash;
public:
hashed_stdstring(const char* _str) : m_str(_str), m_hash(::std::hash<::std::string>()(m_str))
{
}
hashed_stdstring(const ::std::string& _str) : m_str(_str), m_hash(::std::hash<::std::string>()(m_str))
{
}
hashed_stdstring(::std::string&& _str) : m_str(::std::forward<::std::string&&>(_str)), m_hash(::std::hash<::std::string>()(m_str))
{
}
hashed_stdstring(hashed_stdstring&& _other) : m_str(::std::move(_other.m_str)), m_hash(_other.m_hash)
{
}
hashed_stdstring(const char* _str, size_t _hash_code) : m_str(_str), m_hash(_hash_code)
{
}
hashed_stdstring(const ::std::string& _str, size_t _hash_code) : m_str(_str), m_hash(_hash_code)
{
}
hashed_stdstring(::std::string&& _str, size_t _hash_code) : m_str(::std::forward<::std::string&&>(_str)), m_hash(_hash_code)
{
}
hashed_stdstring(const hashed_stdstring&) = default;
hashed_stdstring& operator = (const hashed_stdstring&) = default;
hashed_stdstring& operator = (hashed_stdstring&& _other)
{
m_str = ::std::move(_other.m_str);
m_hash = _other.m_hash;
return *this;
}
inline bool operator == (const hashed_stdstring& _other) const
{
return m_hash == _other.m_hash && m_str == _other.m_str;
}
inline bool operator != (const hashed_stdstring& _other) const
{
return !operator == (_other);
}
inline size_t hcode() const
{
return m_hash;
}
inline const char* c_str() const
{
return m_str.c_str();
}
inline size_t size() const
{
return m_str.size();
}
}; // END of class hashed_stdstring.
} // END of namespace profiler.
namespace std {
/** \brief Simply returns precalculated hash of a std::string. */
template <> struct hash<::profiler::hashed_stdstring> {
typedef ::profiler::hashed_stdstring argument_type;
typedef size_t result_type;
inline size_t operator () (const ::profiler::hashed_stdstring& _str) const {
return _str.hcode();
}
};
} // END of namespace std.
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
#endif // EASY_PROFILER__HASHED_CSTR__H_

View File

@ -0,0 +1,146 @@
/************************************************************************
* file name : easy_compiler_support.h
* ----------------- :
* creation time : 2016/09/22
* authors : Victor Zarubkin, Sergey Yagovtsev
* emails : v.s.zarubkin@gmail.com, yse.sey@gmail.com
* ----------------- :
* description : This file contains auxiliary profiler macros for different compiler support.
* ----------------- :
* license : Lightweight profiler library for c++
* : Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
* :
* :
* : Licensed under the Apache License, Version 2.0 (the "License");
* : you may not use this file except in compliance with the License.
* : You may obtain a copy of the License at
* :
* : http://www.apache.org/licenses/LICENSE-2.0
* :
* : Unless required by applicable law or agreed to in writing, software
* : distributed under the License is distributed on an "AS IS" BASIS,
* : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* : See the License for the specific language governing permissions and
* : limitations under the License.
* :
* :
* : GNU General Public License Usage
* : Alternatively, this file may be used under the terms of the GNU
* : General Public License as published by the Free Software Foundation,
* : either version 3 of the License, or (at your option) any later version.
* :
* : This program is distributed in the hope that it will be useful,
* : but WITHOUT ANY WARRANTY; without even the implied warranty of
* : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
* : GNU General Public License for more details.
* :
* : You should have received a copy of the GNU General Public License
* : along with this program.If not, see <http://www.gnu.org/licenses/>.
************************************************************************/
#ifndef EASY_PROFILER__COMPILER_SUPPORT__H_______
#define EASY_PROFILER__COMPILER_SUPPORT__H_______
#include <cstddef>
//#define EASY_CODE_WRAP(Code) Code
#ifdef _WIN32
// Visual Studio and MinGW
# ifdef _BUILD_PROFILER
# define PROFILER_API __declspec(dllexport)
# else
# define PROFILER_API __declspec(dllimport)
# endif
#endif
#if defined (_MSC_VER)
//////////////////////////////////////////////////////////////////////////
// Visual Studio
# define __func__ __FUNCTION__
# if _MSC_VER <= 1800
// There is no support for C++11 thread_local keyword prior to Visual Studio 2015. Use __declspec(thread) instead.
// There is also no support for C++11 magic statics feature :( So it becomes slightly harder to initialize static vars - additional "if" for each profiler block.
# define EASY_THREAD_LOCAL __declspec(thread)
# define EASY_LOCAL_STATIC_PTR(VarType, VarName, VarInitializer)\
__declspec(thread) static VarType VarName = 0;\
if (!VarName)\
VarName = VarInitializer
# endif
#elif defined (__clang__)
//////////////////////////////////////////////////////////////////////////
// Clang Compiler
# if (__clang_major__ == 3 && __clang_minor__ < 3) || (__clang_major__ < 3)
// There is no support for C++11 thread_local keyword prior to clang 3.3. Use __thread instead.
# define EASY_THREAD_LOCAL __thread
# endif
# if (__clang_major__ == 2 && __clang_minor__ < 9) || (__clang_major__ < 2)
// There is no support for C++11 magic statics feature prior to clang 2.9. It becomes slightly harder to initialize static vars - additional "if" for each profiler block.
# define EASY_LOCAL_STATIC_PTR(VarType, VarName, VarInitializer)\
EASY_THREAD_LOCAL static VarType VarName = 0;\
if (!VarName)\
VarName = VarInitializer
// There is no support for C++11 final keyword prior to clang 2.9
# define EASY_FINAL
# endif
#elif defined(__GNUC__)
//////////////////////////////////////////////////////////////////////////
// GNU Compiler
# if (__GNUC__ == 4 && __GNUC_MINOR__ < 8) || (__GNUC__ < 4)
// There is no support for C++11 thread_local keyword prior to gcc 4.8. Use __thread instead.
# define EASY_THREAD_LOCAL __thread
# endif
# if (__GNUC__ == 4 && __GNUC_MINOR__ < 3) || (__GNUC__ < 4)
// There is no support for C++11 magic statics feature prior to gcc 4.3. It becomes slightly harder to initialize static vars - additional "if" for each profiler block.
# define EASY_LOCAL_STATIC_PTR(VarType, VarName, VarInitializer)\
EASY_THREAD_LOCAL static VarType VarName = 0;\
if (!VarName)\
VarName = VarInitializer
# endif
# if (__GNUC__ == 4 && __GNUC_MINOR__ < 7) || (__GNUC__ < 4)
// There is no support for C++11 final keyword prior to gcc 4.7
# define EASY_FINAL
# endif
#endif
// END // TODO: Add other compilers support
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
// Default values
#ifndef EASY_THREAD_LOCAL
# define EASY_THREAD_LOCAL thread_local
# define EASY_THREAD_LOCAL_CPP11
#endif
#ifndef EASY_LOCAL_STATIC_PTR
# define EASY_LOCAL_STATIC_PTR(VarType, VarName, VarInitializer) static VarType VarName = VarInitializer
# define EASY_MAGIC_STATIC_CPP11
#endif
#ifndef EASY_FINAL
# define EASY_FINAL final
#endif
#ifndef PROFILER_API
# define PROFILER_API
#endif
//////////////////////////////////////////////////////////////////////////
#endif // EASY_PROFILER__COMPILER_SUPPORT__H_______

View File

@ -0,0 +1,130 @@
/**
Lightweight profiler library for c++
Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
GNU General Public License Usage
Alternatively, this file may be used under the terms of the GNU
General Public License as published by the Free Software Foundation,
either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program.If not, see <http://www.gnu.org/licenses/>.
**/
#ifndef EASY_NET_H
#define EASY_NET_H
#include <stdint.h>
namespace profiler {
namespace net {
#define DAFAULT_ADDRESS "tcp://127.0.0.1:28077"
const uint32_t EASY_MESSAGE_SIGN = 20160909;
#pragma pack(push,1)
enum MessageType : uint8_t
{
MESSAGE_TYPE_ZERO = 0,
MESSAGE_TYPE_REQUEST_START_CAPTURE,
MESSAGE_TYPE_REPLY_START_CAPTURING,
MESSAGE_TYPE_REQUEST_STOP_CAPTURE,
MESSAGE_TYPE_REPLY_BLOCKS,
MESSAGE_TYPE_REPLY_BLOCKS_END,
MESSAGE_TYPE_ACCEPTED_CONNECTION,
MESSAGE_TYPE_REQUEST_BLOCKS_DESCRIPTION,
MESSAGE_TYPE_REPLY_BLOCKS_DESCRIPTION,
MESSAGE_TYPE_REPLY_BLOCKS_DESCRIPTION_END,
MESSAGE_TYPE_EDIT_BLOCK_STATUS,
MESSAGE_TYPE_EVENT_TRACING_STATUS,
MESSAGE_TYPE_EVENT_TRACING_PRIORITY,
MESSAGE_TYPE_CHECK_CONNECTION
};
struct Message
{
uint32_t magic_number = EASY_MESSAGE_SIGN;
MessageType type = MESSAGE_TYPE_ZERO;
bool isEasyNetMessage() const
{
return EASY_MESSAGE_SIGN == magic_number;
}
Message() = default;
Message(MessageType _t):type(_t){}
};
struct DataMessage : public Message {
uint32_t size = 0; // bytes
DataMessage(MessageType _t = MESSAGE_TYPE_REPLY_BLOCKS) : Message(_t) {}
DataMessage(uint32_t _s, MessageType _t = MESSAGE_TYPE_REPLY_BLOCKS) : Message(_t), size(_s) {}
const char* data() const { return reinterpret_cast<const char*>(this) + sizeof(DataMessage); }
};
struct BlockStatusMessage : public Message {
uint32_t id;
uint8_t status;
BlockStatusMessage(uint32_t _id, uint8_t _status) : Message(MESSAGE_TYPE_EDIT_BLOCK_STATUS), id(_id), status(_status) { }
private:
BlockStatusMessage() = delete;
};
struct EasyProfilerStatus : public Message
{
bool isProfilerEnabled;
bool isEventTracingEnabled;
bool isLowPriorityEventTracing;
EasyProfilerStatus(bool _enabled, bool _ETenabled, bool _ETlowp)
: Message(MESSAGE_TYPE_ACCEPTED_CONNECTION)
, isProfilerEnabled(_enabled)
, isEventTracingEnabled(_ETenabled)
, isLowPriorityEventTracing(_ETlowp)
{
}
private:
EasyProfilerStatus() = delete;
};
struct BoolMessage : public Message {
bool flag = false;
BoolMessage(MessageType _t, bool _flag = false) : Message(_t), flag(_flag) { }
BoolMessage() = default;
};
#pragma pack(pop)
}//net
}//profiler
#endif // EASY_NET_H

View File

@ -0,0 +1,119 @@
/**
Lightweight profiler library for c++
Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
GNU General Public License Usage
Alternatively, this file may be used under the terms of the GNU
General Public License as published by the Free Software Foundation,
either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program.If not, see <http://www.gnu.org/licenses/>.
**/
#ifndef EASY________SOCKET_________H
#define EASY________SOCKET_________H
#include <stdint.h>
#include "../../../easy_profiler/include/easy/profiler.h"
#ifndef _WIN32
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <netinet/in.h> //for android-build
#else
#define WIN32_LEAN_AND_MEAN
#include <winsock2.h>
#include <windows.h>
#include <ws2tcpip.h>
#include <stdlib.h>
#endif
class PROFILER_API EasySocket
{
public:
#ifdef _WIN32
typedef SOCKET socket_t;
#else
typedef int socket_t;
#endif
enum ConnectionState
{
CONNECTION_STATE_UNKNOWN,
CONNECTION_STATE_SUCCESS,
CONNECTION_STATE_DISCONNECTED,
CONNECTION_STATE_IN_PROGRESS
};
private:
void checkResult(int result);
bool checkSocket(socket_t s) const;
static int _close(socket_t s);
void setBlocking(socket_t s, bool blocking);
socket_t m_socket = 0;
socket_t m_replySocket = 0;
int wsaret = -1;
struct hostent * server;
struct sockaddr_in serv_addr;
ConnectionState m_state = CONNECTION_STATE_UNKNOWN;
public:
EasySocket();
~EasySocket();
int send(const void *buf, size_t nbyte);
int receive(void *buf, size_t nbyte);
int listen(int count=5);
int accept();
int bind(uint16_t portno);
bool setAddress(const char* serv, uint16_t port);
int connect();
void flush();
void init();
void setState(ConnectionState state){m_state=state;}
ConnectionState state() const{return m_state;}
bool isDisconnected() const
{
return m_state == CONNECTION_STATE_UNKNOWN ||
m_state == CONNECTION_STATE_DISCONNECTED;
}
};
#endif // EASY________SOCKET_________H

View File

@ -0,0 +1,682 @@
/**
Lightweight profiler library for c++
Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
GNU General Public License Usage
Alternatively, this file may be used under the terms of the GNU
General Public License as published by the Free Software Foundation,
either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program.If not, see <http://www.gnu.org/licenses/>.
**/
#ifndef EASY_PROFILER____H_______
#define EASY_PROFILER____H_______
#include "../../../easy_profiler/include/easy/profiler_aux.h"
#if defined ( __clang__ )
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
#endif
#ifdef BUILD_WITH_EASY_PROFILER
/**
\defgroup profiler EasyProfiler
*/
/** Indicates that EasyProfiler is used.
\ingroup profiler
*/
#define USING_EASY_PROFILER
// EasyProfiler core API:
/** Macro for beginning of a block with custom name and color.
\code
#include "easy/profiler.h"
void foo()
{
// some code ...
EASY_BLOCK("Check something", profiler::OFF); // Disabled block (There is possibility to enable this block later via GUI)
if(something){
EASY_BLOCK("Calling bar()"); // Block with default color
bar();
}
else{
EASY_BLOCK("Calling baz()", profiler::colors::Red); // Red block
baz();
}
EASY_END_BLOCK; // End of "Check something" block (Even if "Check something" is disabled, this EASY_END_BLOCK will not end any other block).
EASY_BLOCK("Some another block", profiler::colors::Blue, profiler::ON_WITHOUT_CHILDREN); // Block with Blue color without
// some another code...
EASY_BLOCK("Calculate sum"); // This block will not be profiled because it's parent is ON_WITHOUT_CHILDREN
int sum = 0;
for (int i = 0; i < 10; ++i)
sum += i;
EASY_END_BLOCK; // End of "Calculate sum" block
}
\endcode
Block will be automatically completed by destructor.
\ingroup profiler
*/
# define EASY_BLOCK(name, ...)\
EASY_LOCAL_STATIC_PTR(const ::profiler::BaseBlockDescriptor*, EASY_UNIQUE_DESC(__LINE__), ::profiler::registerDescription(::profiler::extract_enable_flag(__VA_ARGS__),\
EASY_UNIQUE_LINE_ID, EASY_COMPILETIME_NAME(name), __FILE__, __LINE__, ::profiler::BLOCK_TYPE_BLOCK, ::profiler::extract_color(__VA_ARGS__),\
::std::is_base_of<::profiler::ForceConstStr, decltype(name)>::value));\
::profiler::Block EASY_UNIQUE_BLOCK(__LINE__)(EASY_UNIQUE_DESC(__LINE__), EASY_RUNTIME_NAME(name));\
::profiler::beginBlock(EASY_UNIQUE_BLOCK(__LINE__)); // this is to avoid compiler warning about unused variable
/** Macro for beginning of a block with function name and custom color.
\code
#include "easy/profiler.h"
void foo(){
EASY_FUNCTION(); // Block with name="foo" and default color
//some code...
}
void bar(){
EASY_FUNCTION(profiler::colors::Green); // Green block with name="bar"
//some code...
}
void baz(){
EASY_FUNCTION(profiler::FORCE_ON); // Force enabled block with name="baz" and default color (This block will be profiled even if it's parent is OFF_RECURSIVE)
// som code...
}
\endcode
Name of the block automatically created with function name.
\ingroup profiler
*/
# define EASY_FUNCTION(...)\
EASY_LOCAL_STATIC_PTR(const ::profiler::BaseBlockDescriptor*, EASY_UNIQUE_DESC(__LINE__), ::profiler::registerDescription(::profiler::extract_enable_flag(__VA_ARGS__),\
EASY_UNIQUE_LINE_ID, __func__, __FILE__, __LINE__, ::profiler::BLOCK_TYPE_BLOCK, ::profiler::extract_color(__VA_ARGS__), false));\
::profiler::Block EASY_UNIQUE_BLOCK(__LINE__)(EASY_UNIQUE_DESC(__LINE__), "");\
::profiler::beginBlock(EASY_UNIQUE_BLOCK(__LINE__)); // this is to avoid compiler warning about unused variable
/** Macro for completion of last opened block.
\code
#include "easy/profiler.h"
int foo()
{
// some code ...
int sum = 0;
EASY_BLOCK("Calculating sum");
for (int i = 0; i < 10; ++i){
sum += i;
}
EASY_END_BLOCK;
// some antoher code here ...
return sum;
}
\endcode
\ingroup profiler
*/
# define EASY_END_BLOCK ::profiler::endBlock();
/** Macro for creating event with custom name and color.
Event is a block with zero duration and special type.
\warning Event ends immidiately and calling EASY_END_BLOCK after EASY_EVENT
will end previously opened EASY_BLOCK or EASY_FUNCTION.
\ingroup profiler
*/
# define EASY_EVENT(name, ...)\
EASY_LOCAL_STATIC_PTR(const ::profiler::BaseBlockDescriptor*, EASY_UNIQUE_DESC(__LINE__), ::profiler::registerDescription(\
::profiler::extract_enable_flag(__VA_ARGS__), EASY_UNIQUE_LINE_ID, EASY_COMPILETIME_NAME(name),\
__FILE__, __LINE__, ::profiler::BLOCK_TYPE_EVENT, ::profiler::extract_color(__VA_ARGS__),\
::std::is_base_of<::profiler::ForceConstStr, decltype(name)>::value));\
::profiler::storeEvent(EASY_UNIQUE_DESC(__LINE__), EASY_RUNTIME_NAME(name));
/** Macro for enabling profiler.
\ingroup profiler
*/
# define EASY_PROFILER_ENABLE ::profiler::setEnabled(true);
/** Macro for disabling profiler.
\ingroup profiler
*/
# define EASY_PROFILER_DISABLE ::profiler::setEnabled(false);
/** Macro for current thread registration.
\note If this thread has been already registered then nothing happens.
\ingroup profiler
*/
# define EASY_THREAD(name)\
EASY_THREAD_LOCAL static const char* EASY_TOKEN_CONCATENATE(unique_profiler_thread_name, __LINE__) = 0;\
if (!EASY_TOKEN_CONCATENATE(unique_profiler_thread_name, __LINE__))\
EASY_TOKEN_CONCATENATE(unique_profiler_thread_name, __LINE__) = ::profiler::registerThread(name);
/** Macro for current thread registration and creating a thread guard object.
\note If this thread has been already registered then nothing happens.
\note Also creates thread guard which marks thread as "expired" on it's destructor
and creates "ThreadFinished" profiler event.
\ingroup profiler
*/
# define EASY_THREAD_SCOPE(name)\
EASY_THREAD_LOCAL static const char* EASY_TOKEN_CONCATENATE(unique_profiler_thread_name, __LINE__) = 0;\
::profiler::ThreadGuard EASY_TOKEN_CONCATENATE(unique_profiler_thread_guard, __LINE__);\
if (!EASY_TOKEN_CONCATENATE(unique_profiler_thread_name, __LINE__))\
EASY_TOKEN_CONCATENATE(unique_profiler_thread_name, __LINE__) = ::profiler::registerThreadScoped(name,\
EASY_TOKEN_CONCATENATE(unique_profiler_thread_guard, __LINE__));
/** Macro for main thread registration.
This is just for user's comfort. There is no difference for EasyProfiler GUI between different threads.
\ingroup profiler
*/
# define EASY_MAIN_THREAD EASY_THREAD("Main")
/** Enable or disable event tracing (context switch events).
\note Default value is controlled by EASY_OPTION_EVENT_TRACING_ENABLED macro.
\note Change will take effect on the next call to EASY_PROFILER_ENABLE.
\sa EASY_PROFILER_ENABLE, EASY_OPTION_EVENT_TRACING_ENABLED
\ingroup profiler
*/
# define EASY_SET_EVENT_TRACING_ENABLED(isEnabled) ::profiler::setEventTracingEnabled(isEnabled);
/** Set event tracing thread priority (low or normal).
Event tracing with low priority will affect your application performance much more less, but
it can be late to gather information about thread/process (thread could be finished to the moment
when event tracing thread will be awaken) and you will not see process name and process id
information in GUI for such threads. You will still be able to see all context switch events.
Event tracing with normal priority could gather more information about processes but potentially
it could affect performance as it has more work to do. Usually you will not notice any performance
breakdown, but if you care about that then you change set event tracing priority level to low.
\sa EASY_OPTION_LOW_PRIORITY_EVENT_TRACING
\ingroup profiler
*/
# define EASY_SET_LOW_PRIORITY_EVENT_TRACING(isLowPriority) ::profiler::setLowPriorityEventTracing(isLowPriority);
/** Macro for setting temporary log-file path for Unix event tracing system.
\note Default value is "/tmp/cs_profiling_info.log".
\ingroup profiler
*/
# define EASY_EVENT_TRACING_SET_LOG(filename) ::profiler::setContextSwitchLogFilename(filename);
/** Macro returning current path to the temporary log-file for Unix event tracing system.
\ingroup profiler
*/
# define EASY_EVENT_TRACING_LOG ::profiler::getContextSwitchLogFilename();
// EasyProfiler settings:
/** If != 0 then EasyProfiler will measure time for blocks storage expansion.
If 0 then EasyProfiler will be compiled without blocks of code responsible
for measuring these events.
These are "EasyProfiler.ExpandStorage" blocks on a diagram.
\ingroup profiler
*/
# ifndef EASY_OPTION_MEASURE_STORAGE_EXPAND
# define EASY_OPTION_MEASURE_STORAGE_EXPAND 0
# endif
# if EASY_OPTION_MEASURE_STORAGE_EXPAND != 0
/** If true then "EasyProfiler.ExpandStorage" blocks are enabled by default and will be
writed to output file or translated over the net.
If false then you need to enable these blocks via GUI if you want to see them.
\ingroup profiler
*/
# ifndef EASY_OPTION_STORAGE_EXPAND_BLOCKS_ON
# define EASY_OPTION_STORAGE_EXPAND_BLOCKS_ON true
# endif
# endif // EASY_OPTION_MEASURE_STORAGE_EXPAND != 0
/** If true then EasyProfiler event tracing is enabled by default
and will be turned on and off when you call profiler::setEnabled().
Otherwise, it have to be turned on via GUI and then it will be
turned on/off with next calls of profiler::setEnabled().
\ingroup profiler
*/
# ifndef EASY_OPTION_EVENT_TRACING_ENABLED
# define EASY_OPTION_EVENT_TRACING_ENABLED true
# endif
/** If true then EasyProfiler.ETW thread (Event tracing for Windows) will have low priority by default.
\sa EASY_SET_LOW_PRIORITY_EVENT_TRACING
\note You can always change priority level via GUI or API while profiling session is not launched.
You don't need to rebuild or restart your application for that.
\ingroup profiler
*/
# ifndef EASY_OPTION_LOW_PRIORITY_EVENT_TRACING
# define EASY_OPTION_LOW_PRIORITY_EVENT_TRACING true
# endif
/** If != 0 then EasyProfiler will print error messages into stderr.
Otherwise, no log messages will be printed.
\ingroup profiler
*/
# ifndef EASY_OPTION_LOG_ENABLED
# define EASY_OPTION_LOG_ENABLED 0
# endif
/** If != 0 then EasyProfiler will start listening thread immidiately on ProfileManager initialization.
\sa startListen
\ingroup profiler
*/
# ifndef EASY_OPTION_START_LISTEN_ON_STARTUP
# define EASY_OPTION_START_LISTEN_ON_STARTUP 0
# endif
#else // #ifdef BUILD_WITH_EASY_PROFILER
# define EASY_BLOCK(...)
# define EASY_FUNCTION(...)
# define EASY_END_BLOCK
# define EASY_PROFILER_ENABLE
# define EASY_PROFILER_DISABLE
# define EASY_EVENT(...)
# define EASY_THREAD(...)
# define EASY_THREAD_SCOPE(...)
# define EASY_MAIN_THREAD
# define EASY_SET_EVENT_TRACING_ENABLED(isEnabled)
# define EASY_SET_LOW_PRIORITY_EVENT_TRACING(isLowPriority)
# ifndef _WIN32
# define EASY_EVENT_TRACING_SET_LOG(filename)
# define EASY_EVENT_TRACING_LOG ""
# endif
# ifndef EASY_OPTION_MEASURE_STORAGE_EXPAND
# define EASY_OPTION_MEASURE_STORAGE_EXPAND 0
# endif
# ifndef EASY_OPTION_EVENT_TRACING_ENABLED
# define EASY_OPTION_EVENT_TRACING_ENABLED false
# endif
# ifndef EASY_OPTION_LOW_PRIORITY_EVENT_TRACING
# define EASY_OPTION_LOW_PRIORITY_EVENT_TRACING true
# endif
# ifndef EASY_OPTION_LOG_ENABLED
# define EASY_OPTION_LOG_ENABLED 0
# endif
# ifndef EASY_OPTION_START_LISTEN_ON_STARTUP
# define EASY_OPTION_START_LISTEN_ON_STARTUP 0
# endif
#endif // #ifndef BUILD_WITH_EASY_PROFILER
# ifndef EASY_DEFAULT_PORT
# define EASY_DEFAULT_PORT 28077
# endif
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
class ProfileManager;
struct ThreadStorage;
namespace profiler {
//////////////////////////////////////////////////////////////////////
// Core types
const uint16_t DEFAULT_PORT = EASY_DEFAULT_PORT;
typedef uint64_t timestamp_t;
typedef uint32_t thread_id_t;
typedef uint32_t block_id_t;
enum BlockType : uint8_t
{
BLOCK_TYPE_EVENT = 0,
BLOCK_TYPE_BLOCK,
BLOCK_TYPES_NUMBER
};
typedef BlockType block_type_t;
//***********************************************
#pragma pack(push,1)
class PROFILER_API BaseBlockDescriptor
{
friend ::ProfileManager;
friend ::ThreadStorage;
protected:
block_id_t m_id; ///< This descriptor id (We can afford this spending because there are much more blocks than descriptors)
int m_line; ///< Line number in the source file
color_t m_color; ///< Color of the block packed into 1-byte structure
block_type_t m_type; ///< Type of the block (See BlockType)
EasyBlockStatus m_status; ///< If false then blocks with such id() will not be stored by profiler during profile session
BaseBlockDescriptor(block_id_t _id, EasyBlockStatus _status, int _line, block_type_t _block_type, color_t _color);
public:
inline block_id_t id() const { return m_id; }
inline int line() const { return m_line; }
inline color_t color() const { return m_color; }
inline block_type_t type() const { return m_type; }
inline EasyBlockStatus status() const { return m_status; }
}; // END of class BaseBlockDescriptor.
//***********************************************
class PROFILER_API BaseBlockData
{
friend ::ProfileManager;
protected:
timestamp_t m_begin;
timestamp_t m_end;
block_id_t m_id;
public:
BaseBlockData(const BaseBlockData&) = default;
BaseBlockData(timestamp_t _begin_time, block_id_t _id);
inline timestamp_t begin() const { return m_begin; }
inline timestamp_t end() const { return m_end; }
inline block_id_t id() const { return m_id; }
inline timestamp_t duration() const { return m_end - m_begin; }
inline void setId(block_id_t _id) { m_id = _id; }
private:
BaseBlockData() = delete;
}; // END of class BaseBlockData.
#pragma pack(pop)
//***********************************************
class PROFILER_API Block EASY_FINAL : public BaseBlockData
{
friend ::ProfileManager;
friend ::ThreadStorage;
const char* m_name;
EasyBlockStatus m_status;
private:
void start();
void start(timestamp_t _time);
void finish();
void finish(timestamp_t _time);
inline bool finished() const { return m_end >= m_begin; }
inline EasyBlockStatus status() const { return m_status; }
inline void setStatus(EasyBlockStatus _status) { m_status = _status; }
public:
Block(Block&& that);
Block(const BaseBlockDescriptor* _desc, const char* _runtimeName);
Block(timestamp_t _begin_time, block_id_t _id, const char* _runtimeName);
~Block();
inline const char* name() const { return m_name; }
private:
Block(const Block&) = delete;
Block& operator = (const Block&) = delete;
}; // END of class Block.
//***********************************************
class PROFILER_API ThreadGuard EASY_FINAL {
friend ::ProfileManager;
thread_id_t m_id = 0;
public:
~ThreadGuard();
};
//////////////////////////////////////////////////////////////////////
// Core API
// Note: it is better to use macros defined above than a direct calls to API.
#ifdef BUILD_WITH_EASY_PROFILER
extern "C" {
/** Registers static description of a block.
It is general information which is common for all such blocks.
Includes color, block type (see BlockType), file-name, line-number, compile-time name of a block and enable-flag.
\ingroup profiler
*/
PROFILER_API const BaseBlockDescriptor* registerDescription(EasyBlockStatus _status, const char* _autogenUniqueId, const char* _compiletimeName, const char* _filename, int _line, block_type_t _block_type, color_t _color, bool _copyName = false);
/** Stores event in the blocks list.
An event ends instantly and has zero duration.
\param _desc Reference to the previously registered description.
\param _runtimeName Standard zero-terminated string which will be copied to the events buffer.
\ingroup profiler
*/
PROFILER_API void storeEvent(const BaseBlockDescriptor* _desc, const char* _runtimeName);
/** Begins block.
\ingroup profiler
*/
PROFILER_API void beginBlock(Block& _block);
/** Ends last started block.
\ingroup profiler
*/
PROFILER_API void endBlock();
/** Enable or disable profiler.
\ingroup profiler
*/
PROFILER_API void setEnabled(bool _isEnable);
PROFILER_API bool isEnabled();
/** Save all gathered blocks into file.
\note This also disables profiler.
\ingroup profiler
*/
PROFILER_API uint32_t dumpBlocksToFile(const char* _filename);
/** Register current thread and give it a name.
\note Only first call of registerThread() for the current thread will have an effect.
\ingroup profiler
*/
PROFILER_API const char* registerThreadScoped(const char* _name, ThreadGuard&);
/** Register current thread and give it a name.
\note Only first call of registerThread() for the current thread will have an effect.
\ingroup profiler
*/
PROFILER_API const char* registerThread(const char* _name);
/** Enable or disable event tracing.
\note This change will take an effect on the next call of setEnabled(true);
\sa setEnabled, EASY_SET_EVENT_TRACING_ENABLED
\ingroup profiler
*/
PROFILER_API void setEventTracingEnabled(bool _isEnable);
PROFILER_API bool isEventTracingEnabled();
/** Set event tracing thread priority (low or normal).
\note This change will take effect on the next call of setEnabled(true);
\sa setEnabled, EASY_SET_LOW_PRIORITY_EVENT_TRACING
\ingroup profiler
*/
PROFILER_API void setLowPriorityEventTracing(bool _isLowPriority);
PROFILER_API bool isLowPriorityEventTracing();
/** Set temporary log-file path for Unix event tracing system.
\note Default value is "/tmp/cs_profiling_info.log".
\ingroup profiler
*/
PROFILER_API void setContextSwitchLogFilename(const char* _name);
/** Returns current path to the temporary log-file for Unix event tracing system.
\ingroup profiler
*/
PROFILER_API const char* getContextSwitchLogFilename();
PROFILER_API void startListen(uint16_t _port = ::profiler::DEFAULT_PORT);
PROFILER_API void stopListen();
PROFILER_API bool isListening();
/** Returns current major version.
\ingroup profiler
*/
PROFILER_API uint8_t versionMajor();
/** Returns current minor version.
\ingroup profiler
*/
PROFILER_API uint8_t versionMinor();
/** Returns current version patch.
\ingroup profiler
*/
PROFILER_API uint16_t versionPatch();
/** Returns current version in 32-bit integer format.
\ingroup profiler
*/
PROFILER_API uint32_t version();
/** Returns current version in 32-bit integer format.
\ingroup profiler
*/
PROFILER_API const char* versionName();
}
#else
inline const BaseBlockDescriptor* registerDescription(EasyBlockStatus, const char*, const char*, const char*, int, block_type_t, color_t, bool = false)
{ return reinterpret_cast<const BaseBlockDescriptor*>(0xbad); }
inline void endBlock() { }
inline void setEnabled(bool) { }
inline bool isEnabled(bool) { return false; }
inline void storeEvent(const BaseBlockDescriptor*, const char*) { }
inline void beginBlock(Block&) { }
inline uint32_t dumpBlocksToFile(const char*) { return 0; }
inline const char* registerThreadScoped(const char*, ThreadGuard&) { return ""; }
inline const char* registerThread(const char*) { return ""; }
inline void setEventTracingEnabled(bool) { }
inline bool isEventTracingEnabled() { return false; }
inline void setLowPriorityEventTracing(bool) { }
inline bool isLowPriorityEventTracing() { return false; }
inline void setContextSwitchLogFilename(const char*) { }
inline const char* getContextSwitchLogFilename() { return ""; }
inline void startListen(uint16_t = ::profiler::DEFAULT_PORT) { }
inline void stopListen() { }
inline bool isListening() { return false; }
inline uint8_t versionMajor() { return 0; }
inline uint8_t versionMinor() { return 0; }
inline uint16_t versionPatch() { return 0; }
inline uint32_t version() { return 0; }
inline const char* versionName() { return "v0.0.0_disabled"; }
#endif
//////////////////////////////////////////////////////////////////////
} // END of namespace profiler.
#if defined ( __clang__ )
# pragma clang diagnostic pop
#endif
#endif // EASY_PROFILER____H_______

View File

@ -0,0 +1,198 @@
/************************************************************************
* file name : profiler_aux.h
* ----------------- :
* creation time : 2016/06/11
* author : Victor Zarubkin
* email : v.s.zarubkin@gmail.com
* ----------------- :
* description : This file contains auxiliary profiler macros and funcitons.
* ----------------- :
* change log : * 2016/06/11 Victor Zarubkin: Moved sources from profiler.h
* :
* : *
* ----------------- :
* license : Lightweight profiler library for c++
* : Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
* :
* :
* : Licensed under the Apache License, Version 2.0 (the "License");
* : you may not use this file except in compliance with the License.
* : You may obtain a copy of the License at
* :
* : http://www.apache.org/licenses/LICENSE-2.0
* :
* : Unless required by applicable law or agreed to in writing, software
* : distributed under the License is distributed on an "AS IS" BASIS,
* : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* : See the License for the specific language governing permissions and
* : limitations under the License.
* :
* :
* : GNU General Public License Usage
* : Alternatively, this file may be used under the terms of the GNU
* : General Public License as published by the Free Software Foundation,
* : either version 3 of the License, or (at your option) any later version.
* :
* : This program is distributed in the hope that it will be useful,
* : but WITHOUT ANY WARRANTY; without even the implied warranty of
* : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
* : GNU General Public License for more details.
* :
* : You should have received a copy of the GNU General Public License
* : along with this program.If not, see <http://www.gnu.org/licenses/>.
************************************************************************/
#ifndef EASY_PROFILER__AUX__H_______
#define EASY_PROFILER__AUX__H_______
#include <stdint.h>
#include "../../../easy_profiler/include/easy/easy_compiler_support.h"
#include "../../../easy_profiler/include/easy/profiler_colors.h"
//////////////////////////////////////////////////////////////////////////
namespace profiler {
enum EasyBlockStatus : uint8_t {
OFF = 0, ///< The block is OFF
ON = 1, ///< The block is ON (but if it's parent block is off recursively then this block will be off too)
FORCE_ON = ON | 2, ///< The block is ALWAYS ON (even if it's parent has turned off all children)
OFF_RECURSIVE = 4, ///< The block is OFF and all of it's children by call-stack are also OFF.
ON_WITHOUT_CHILDREN = ON | OFF_RECURSIVE, ///< The block is ON but all of it's children are OFF.
FORCE_ON_WITHOUT_CHILDREN = FORCE_ON | OFF_RECURSIVE, ///< The block is ALWAYS ON but all of it's children are OFF.
};
struct passthrough_hash EASY_FINAL {
template <class T> inline size_t operator () (T _value) const {
return static_cast<size_t>(_value);
}
};
}
//////////////////////////////////////////////////////////////////////////
#include <type_traits>
#include <string>
# define EASY_STRINGIFY(a) #a
# define EASY_STRINGIFICATION(a) EASY_STRINGIFY(a)
# define EASY_TOKEN_JOIN(x, y) x ## y
# define EASY_TOKEN_CONCATENATE(x, y) EASY_TOKEN_JOIN(x, y)
# define EASY_UNIQUE_BLOCK(x) EASY_TOKEN_CONCATENATE(unique_profiler_mark_name_, x)
# define EASY_UNIQUE_DESC(x) EASY_TOKEN_CONCATENATE(unique_profiler_descriptor_, x)
#ifdef BUILD_WITH_EASY_PROFILER
namespace profiler {
template <const bool> struct NameSwitch;
class ForceConstStr EASY_FINAL {
friend NameSwitch<true>;
friend NameSwitch<false>;
const char* c_str;
ForceConstStr() = delete;
ForceConstStr(const ForceConstStr&) = delete;
ForceConstStr(ForceConstStr&&) = delete;
ForceConstStr& operator = (const ForceConstStr&) = delete;
ForceConstStr& operator = (ForceConstStr&&) = delete;
public:
ForceConstStr(const char* _str) : c_str(_str) {}
ForceConstStr(const ::std::string& _str) : c_str(_str.c_str()) {}
};
template <const bool IS_REF> struct NameSwitch EASY_FINAL {
static const char* runtime_name(const char* name) { return name; }
static const char* runtime_name(const ::std::string& name) { return name.c_str(); }
static const char* runtime_name(const ForceConstStr&) { return ""; }
template <class T>
static const char* compiletime_name(const T&, const char* autoGeneratedName) { return autoGeneratedName; }
static const char* compiletime_name(const char*, const char* autoGeneratedName) { return autoGeneratedName; }
static const char* compiletime_name(const ForceConstStr& name, const char*) { return name.c_str; }
};
template <> struct NameSwitch<true> EASY_FINAL {
static const char* runtime_name(const char*) { return ""; }
static const char* runtime_name(const ::std::string& name) { return name.c_str(); }
static const char* runtime_name(const ForceConstStr&) { return ""; }
template <class T>
static const char* compiletime_name(const T&, const char* autoGeneratedName) { return autoGeneratedName; }
static const char* compiletime_name(const char* name, const char*) { return name; }
static const char* compiletime_name(const ForceConstStr& name, const char*) { return name.c_str; }
};
//***********************************************
inline color_t extract_color() {
return ::profiler::colors::Default;
}
template <class ... TArgs>
inline color_t extract_color(::profiler::EasyBlockStatus, TArgs...) {
return ::profiler::colors::Default;
}
template <class ... TArgs>
inline color_t extract_color(color_t _color, TArgs...) {
return _color;
}
template <class T, class ... TArgs>
inline color_t extract_color(T, color_t _color, TArgs...) {
return _color;
}
template <class ... TArgs>
inline color_t extract_color(TArgs...) {
static_assert(sizeof...(TArgs) < 2, "No profiler::color_t in arguments list for EASY_BLOCK(name, ...)!");
return ::profiler::colors::Default;
}
//***********************************************
inline EasyBlockStatus extract_enable_flag() {
return ::profiler::ON;
}
template <class T, class ... TArgs>
inline EasyBlockStatus extract_enable_flag(T, ::profiler::EasyBlockStatus _flag, TArgs...) {
return _flag;
}
template <class ... TArgs>
inline EasyBlockStatus extract_enable_flag(::profiler::EasyBlockStatus _flag, TArgs...) {
return _flag;
}
template <class ... TArgs>
inline EasyBlockStatus extract_enable_flag(TArgs...) {
static_assert(sizeof...(TArgs) < 2, "No EasyBlockStatus in arguments list for EASY_BLOCK(name, ...)!");
return ::profiler::ON;
}
//***********************************************
} // END of namespace profiler.
# define EASY_UNIQUE_LINE_ID __FILE__ ":" EASY_STRINGIFICATION(__LINE__)
# define EASY_COMPILETIME_NAME(name) ::profiler::NameSwitch<::std::is_reference<decltype(name)>::value>::compiletime_name(name, EASY_UNIQUE_LINE_ID)
# define EASY_RUNTIME_NAME(name) ::profiler::NameSwitch<::std::is_reference<decltype(name)>::value>::runtime_name(name)
# define EASY_CONST_NAME(name) ::profiler::ForceConstStr(name)
#else
# define EASY_CONST_NAME(name)
#endif // BUILD_WITH_EASY_PROFILER
//////////////////////////////////////////////////////////////////////////
#endif // EASY_PROFILER__AUX__H_______

View File

@ -0,0 +1,402 @@
/**
Lightweight profiler library for c++
Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
GNU General Public License Usage
Alternatively, this file may be used under the terms of the GNU
General Public License as published by the Free Software Foundation,
either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program.If not, see <http://www.gnu.org/licenses/>.
**/
#ifndef EASY_PROFILER__COLORS__H_______
#define EASY_PROFILER__COLORS__H_______
#include <stdint.h>
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
namespace profiler {
typedef uint32_t color_t; // Standard four-byte ARGB color format
namespace colors {
///< Change alpha for color. Only 8 major bytes (0xff000000) used from alpha.
inline color_t modify_alpha32(color_t _color, color_t _alpha) {
return (_alpha & 0xff000000) | (_color & 0x00ffffff);
}
///< Change alpha for color.
inline color_t modify_alpha8(color_t _color, uint8_t _alpha) {
return (static_cast<color_t>(_alpha) << 24) | (_color & 0x00ffffff);
}
///< Create color from ARGB components.
inline color_t color(uint8_t _red, uint8_t _green, uint8_t _blue, uint8_t _alpha = 0xff) {
return (static_cast<color_t>(_alpha) << 24) | (static_cast<color_t>(_red) << 16) | (static_cast<color_t>(_green) << 8) | static_cast<color_t>(_blue);
}
#if !defined(EASY_OPTION_BUILTIN_COLORS) || EASY_OPTION_BUILTIN_COLORS != 0
// Google Material Design colors
// See https://material.google.com/style/color.html
const color_t Red50 = 0xffffebee;
const color_t Red100 = 0xffffcdd2;
const color_t Red200 = 0xffef9a9a;
const color_t Red300 = 0xffe57373;
const color_t Red400 = 0xffef5350;
const color_t Red500 = 0xfff44336;
const color_t Red600 = 0xffe53935;
const color_t Red700 = 0xffd32f2f;
const color_t Red800 = 0xffc62828;
const color_t Red900 = 0xffb71c1c;
const color_t RedA100 = 0xffff8a80;
const color_t RedA200 = 0xffff5252;
const color_t RedA400 = 0xffff1744;
const color_t RedA700 = 0xffd50000;
const color_t Pink50 = 0xfffce4ec;
const color_t Pink100 = 0xfff8bbd0;
const color_t Pink200 = 0xfff48fb1;
const color_t Pink300 = 0xfff06292;
const color_t Pink400 = 0xffec407a;
const color_t Pink500 = 0xffe91e63;
const color_t Pink600 = 0xffd81b60;
const color_t Pink700 = 0xffc2185b;
const color_t Pink800 = 0xffad1457;
const color_t Pink900 = 0xff880e4f;
const color_t PinkA100 = 0xffff80ab;
const color_t PinkA200 = 0xffff4081;
const color_t PinkA400 = 0xfff50057;
const color_t PinkA700 = 0xffc51162;
const color_t Purple50 = 0xfff3e5f5;
const color_t Purple100 = 0xffe1bee7;
const color_t Purple200 = 0xffce93d8;
const color_t Purple300 = 0xffba68c8;
const color_t Purple400 = 0xffab47bc;
const color_t Purple500 = 0xff9c27b0;
const color_t Purple600 = 0xff8e24aa;
const color_t Purple700 = 0xff7b1fa2;
const color_t Purple800 = 0xff6a1b9a;
const color_t Purple900 = 0xff4a148c;
const color_t PurpleA100 = 0xffea80fc;
const color_t PurpleA200 = 0xffe040fb;
const color_t PurpleA400 = 0xffd500f9;
const color_t PurpleA700 = 0xffaa00ff;
const color_t DeepPurple50 = 0xffede7f6;
const color_t DeepPurple100 = 0xffd1c4e9;
const color_t DeepPurple200 = 0xffb39ddb;
const color_t DeepPurple300 = 0xff9575cd;
const color_t DeepPurple400 = 0xff7e57c2;
const color_t DeepPurple500 = 0xff673ab7;
const color_t DeepPurple600 = 0xff5e35b1;
const color_t DeepPurple700 = 0xff512da8;
const color_t DeepPurple800 = 0xff4527a0;
const color_t DeepPurple900 = 0xff311b92;
const color_t DeepPurpleA100 = 0xffb388ff;
const color_t DeepPurpleA200 = 0xff7c4dff;
const color_t DeepPurpleA400 = 0xff651fff;
const color_t DeepPurpleA700 = 0xff6200ea;
const color_t Indigo50 = 0xffe8eaf6;
const color_t Indigo100 = 0xffc5cae9;
const color_t Indigo200 = 0xff9fa8da;
const color_t Indigo300 = 0xff7986cb;
const color_t Indigo400 = 0xff5c6bc0;
const color_t Indigo500 = 0xff3f51b5;
const color_t Indigo600 = 0xff3949ab;
const color_t Indigo700 = 0xff303f9f;
const color_t Indigo800 = 0xff283593;
const color_t Indigo900 = 0xff1a237e;
const color_t IndigoA100 = 0xff8c9eff;
const color_t IndigoA200 = 0xff536dfe;
const color_t IndigoA400 = 0xff3d5afe;
const color_t IndigoA700 = 0xff304ffe;
const color_t Blue50 = 0xffe3f2fd;
const color_t Blue100 = 0xffbbdefb;
const color_t Blue200 = 0xff90caf9;
const color_t Blue300 = 0xff64b5f6;
const color_t Blue400 = 0xff42a5f5;
const color_t Blue500 = 0xff2196f3;
const color_t Blue600 = 0xff1e88e5;
const color_t Blue700 = 0xff1976d2;
const color_t Blue800 = 0xff1565c0;
const color_t Blue900 = 0xff0d47a1;
const color_t BlueA100 = 0xff82b1ff;
const color_t BlueA200 = 0xff448aff;
const color_t BlueA400 = 0xff2979ff;
const color_t BlueA700 = 0xff2962ff;
const color_t LightBlue50 = 0xffe1f5fe;
const color_t LightBlue100 = 0xffb3e5fc;
const color_t LightBlue200 = 0xff81d4fa;
const color_t LightBlue300 = 0xff4fc3f7;
const color_t LightBlue400 = 0xff29b6f6;
const color_t LightBlue500 = 0xff03a9f4;
const color_t LightBlue600 = 0xff039be5;
const color_t LightBlue700 = 0xff0288d1;
const color_t LightBlue800 = 0xff0277bd;
const color_t LightBlue900 = 0xff01579b;
const color_t LightBlueA100 = 0xff80d8ff;
const color_t LightBlueA200 = 0xff40c4ff;
const color_t LightBlueA400 = 0xff00b0ff;
const color_t LightBlueA700 = 0xff0091ea;
const color_t Cyan50 = 0xffe0f7fa;
const color_t Cyan100 = 0xffb2ebf2;
const color_t Cyan200 = 0xff80deea;
const color_t Cyan300 = 0xff4dd0e1;
const color_t Cyan400 = 0xff26c6da;
const color_t Cyan500 = 0xff00bcd4;
const color_t Cyan600 = 0xff00acc1;
const color_t Cyan700 = 0xff0097a7;
const color_t Cyan800 = 0xff00838f;
const color_t Cyan900 = 0xff006064;
const color_t CyanA100 = 0xff84ffff;
const color_t CyanA200 = 0xff18ffff;
const color_t CyanA400 = 0xff00e5ff;
const color_t CyanA700 = 0xff00b8d4;
const color_t Teal50 = 0xffe0f2f1;
const color_t Teal100 = 0xffb2dfdb;
const color_t Teal200 = 0xff80cbc4;
const color_t Teal300 = 0xff4db6ac;
const color_t Teal400 = 0xff26a69a;
const color_t Teal500 = 0xff009688;
const color_t Teal600 = 0xff00897b;
const color_t Teal700 = 0xff00796b;
const color_t Teal800 = 0xff00695c;
const color_t Teal900 = 0xff004d40;
const color_t TealA100 = 0xffa7ffeb;
const color_t TealA200 = 0xff64ffda;
const color_t TealA400 = 0xff1de9b6;
const color_t TealA700 = 0xff00bfa5;
const color_t Green50 = 0xffe8f5e9;
const color_t Green100 = 0xffc8e6c9;
const color_t Green200 = 0xffa5d6a7;
const color_t Green300 = 0xff81c784;
const color_t Green400 = 0xff66bb6a;
const color_t Green500 = 0xff4caf50;
const color_t Green600 = 0xff43a047;
const color_t Green700 = 0xff388e3c;
const color_t Green800 = 0xff2e7d32;
const color_t Green900 = 0xff1b5e20;
const color_t GreenA100 = 0xffb9f6ca;
const color_t GreenA200 = 0xff69f0ae;
const color_t GreenA400 = 0xff00e676;
const color_t GreenA700 = 0xff00c853;
const color_t LightGreen50 = 0xfff1f8e9;
const color_t LightGreen100 = 0xffdcedc8;
const color_t LightGreen200 = 0xffc5e1a5;
const color_t LightGreen300 = 0xffaed581;
const color_t LightGreen400 = 0xff9ccc65;
const color_t LightGreen500 = 0xff8bc34a;
const color_t LightGreen600 = 0xff7cb342;
const color_t LightGreen700 = 0xff689f38;
const color_t LightGreen800 = 0xff558b2f;
const color_t LightGreen900 = 0xff33691e;
const color_t LightGreenA100 = 0xffccff90;
const color_t LightGreenA200 = 0xffb2ff59;
const color_t LightGreenA400 = 0xff76ff03;
const color_t LightGreenA700 = 0xff64dd17;
const color_t Lime50 = 0xfff9ebe7;
const color_t Lime100 = 0xfff0f4c3;
const color_t Lime200 = 0xffe6ee9c;
const color_t Lime300 = 0xffdce775;
const color_t Lime400 = 0xffd4e157;
const color_t Lime500 = 0xffcddc39;
const color_t Lime600 = 0xffc0ca33;
const color_t Lime700 = 0xffafb42b;
const color_t Lime800 = 0xff9e9d24;
const color_t Lime900 = 0xff827717;
const color_t LimeA100 = 0xfff4ff81;
const color_t LimeA200 = 0xffeeff41;
const color_t LimeA400 = 0xffc6ff00;
const color_t LimeA700 = 0xffaeea00;
const color_t Yellow50 = 0xfffffde7;
const color_t Yellow100 = 0xfffff9c4;
const color_t Yellow200 = 0xfffff59d;
const color_t Yellow300 = 0xfffff176;
const color_t Yellow400 = 0xffffee58;
const color_t Yellow500 = 0xffffeb3b;
const color_t Yellow600 = 0xfffdd835;
const color_t Yellow700 = 0xfffbc02d;
const color_t Yellow800 = 0xfff9a825;
const color_t Yellow900 = 0xfff57f17;
const color_t YellowA100 = 0xffffff8d;
const color_t YellowA200 = 0xffffff00;
const color_t YellowA400 = 0xffffea00;
const color_t YellowA700 = 0xffffd600;
const color_t Amber50 = 0xfffff8e1;
const color_t Amber100 = 0xffffecb3;
const color_t Amber200 = 0xffffe082;
const color_t Amber300 = 0xffffd54f;
const color_t Amber400 = 0xffffca28;
const color_t Amber500 = 0xffffc107;
const color_t Amber600 = 0xffffb300;
const color_t Amber700 = 0xffffa000;
const color_t Amber800 = 0xffff8f00;
const color_t Amber900 = 0xffff6f00;
const color_t AmberA100 = 0xffffe57f;
const color_t AmberA200 = 0xffffd740;
const color_t AmberA400 = 0xffffc400;
const color_t AmberA700 = 0xffffab00;
const color_t Orange50 = 0xfffff3e0;
const color_t Orange100 = 0xffffe0b2;
const color_t Orange200 = 0xffffcc80;
const color_t Orange300 = 0xffffb74d;
const color_t Orange400 = 0xffffa726;
const color_t Orange500 = 0xffff9800;
const color_t Orange600 = 0xfffb8c00;
const color_t Orange700 = 0xfff57c00;
const color_t Orange800 = 0xffef6c00;
const color_t Orange900 = 0xffe65100;
const color_t OrangeA100 = 0xffffd180;
const color_t OrangeA200 = 0xffffab40;
const color_t OrangeA400 = 0xffff9100;
const color_t OrangeA700 = 0xffff6d00;
const color_t DeepOrange50 = 0xfffbe9e7;
const color_t DeepOrange100 = 0xffffccbc;
const color_t DeepOrange200 = 0xffffab91;
const color_t DeepOrange300 = 0xffff8a65;
const color_t DeepOrange400 = 0xffff7043;
const color_t DeepOrange500 = 0xffff5722;
const color_t DeepOrange600 = 0xfff4511e;
const color_t DeepOrange700 = 0xffe64a19;
const color_t DeepOrange800 = 0xffd84315;
const color_t DeepOrange900 = 0xffbf360c;
const color_t DeepOrangeA100 = 0xffff9e80;
const color_t DeepOrangeA200 = 0xffff6e40;
const color_t DeepOrangeA400 = 0xffff3d00;
const color_t DeepOrangeA700 = 0xffdd2c00;
const color_t Brown50 = 0xffefebe9;
const color_t Brown100 = 0xffd7ccc8;
const color_t Brown200 = 0xffbcaaa4;
const color_t Brown300 = 0xffa1887f;
const color_t Brown400 = 0xff8d6e63;
const color_t Brown500 = 0xff795548;
const color_t Brown600 = 0xff6d4c41;
const color_t Brown700 = 0xff5d4037;
const color_t Brown800 = 0xff4e342e;
const color_t Brown900 = 0xff3e2723;
const color_t Grey50 = 0xfffafafa;
const color_t Grey100 = 0xfff5f5f5;
const color_t Grey200 = 0xffeeeeee;
const color_t Grey300 = 0xffe0e0e0;
const color_t Grey400 = 0xffbdbdbd;
const color_t Grey500 = 0xff9e9e9e;
const color_t Grey600 = 0xff757575;
const color_t Grey700 = 0xff616161;
const color_t Grey800 = 0xff424242;
const color_t Grey900 = 0xff212121;
const color_t BlueGrey50 = 0xffeceff1;
const color_t BlueGrey100 = 0xffcfd8dc;
const color_t BlueGrey200 = 0xffb0bec5;
const color_t BlueGrey300 = 0xff90a4ae;
const color_t BlueGrey400 = 0xff78909c;
const color_t BlueGrey500 = 0xff607d8b;
const color_t BlueGrey600 = 0xff546e7a;
const color_t BlueGrey700 = 0xff455a64;
const color_t BlueGrey800 = 0xff37474f;
const color_t BlueGrey900 = 0xff263238;
const color_t Black = 0xff000000;
const color_t White = 0xffffffff;
const color_t Null = 0x00000000;
const color_t Red = Red500;
const color_t DarkRed = Red900;
const color_t Coral = Red200;
const color_t RichRed = 0xffff0000;
const color_t Pink = Pink500;
const color_t Rose = PinkA100;
const color_t Purple = Purple500;
const color_t Magenta = PurpleA200;
const color_t DarkMagenta = PurpleA700;
const color_t DeepPurple = DeepPurple500;
const color_t Indigo = Indigo500;
const color_t Blue = Blue500;
const color_t DarkBlue = Blue900;
const color_t RichBlue = 0xff0000ff;
const color_t LightBlue = LightBlue500;
const color_t SkyBlue = LightBlueA100;
const color_t Navy = LightBlue800;
const color_t Cyan = Cyan500;
const color_t DarkCyan = Cyan900;
const color_t Teal = Teal500;
const color_t DarkTeal = Teal900;
const color_t Green = Green500;
const color_t DarkGreen = Green900;
const color_t RichGreen = 0xff00ff00;
const color_t LightGreen = LightGreen500;
const color_t Mint = LightGreen900;
const color_t Lime = Lime500;
const color_t Olive = Lime900;
const color_t Yellow = Yellow500;
const color_t RichYellow = YellowA200;
const color_t Amber = Amber500;
const color_t Gold = Amber300;
const color_t PaleGold = AmberA100;
const color_t Orange = Orange500;
const color_t Skin = Orange100;
const color_t DeepOrange = DeepOrange500;
const color_t Brick = DeepOrange900;
const color_t Brown = Brown500;
const color_t DarkBrown = Brown900;
const color_t CreamWhite = Orange50;
const color_t Wheat = Amber100;
const color_t Grey = Grey500;
const color_t Dark = Grey900;
const color_t Silver = Grey300;
const color_t BlueGrey = BlueGrey500;
const color_t Default = Wheat;
#else
const color_t Default = 0xffffecb3;
#endif // #if !defined(EASY_OPTION_BUILTIN_COLORS) || EASY_OPTION_BUILTIN_COLORS == 0
} // END of namespace colors.
} // END of namespace profiler.
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
#endif // EASY_PROFILER__COLORS__H_______

View File

@ -0,0 +1,404 @@
/**
Lightweight profiler library for c++
Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
GNU General Public License Usage
Alternatively, this file may be used under the terms of the GNU
General Public License as published by the Free Software Foundation,
either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program.If not, see <http://www.gnu.org/licenses/>.
**/
#ifndef PROFILER_READER____H
#define PROFILER_READER____H
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include <unordered_map>
#include <vector>
#include <string>
#include <atomic>
#include "../../../easy_profiler/include/easy/profiler.h"
#include "../../../easy_profiler/include/easy/serialized_block.h"
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
namespace profiler {
typedef uint32_t calls_number_t;
typedef uint32_t block_index_t;
#pragma pack(push, 1)
struct BlockStatistics EASY_FINAL
{
::profiler::timestamp_t total_duration; ///< Total duration of all block calls
::profiler::block_index_t min_duration_block; ///< Will be used in GUI to jump to the block with min duration
::profiler::block_index_t max_duration_block; ///< Will be used in GUI to jump to the block with max duration
::profiler::block_index_t parent_block; ///< Index of block which is "parent" for "per_parent_stats" or "frame" for "per_frame_stats" or thread-id for "per_thread_stats"
::profiler::calls_number_t calls_number; ///< Block calls number
explicit BlockStatistics(::profiler::timestamp_t _duration, ::profiler::block_index_t _block_index, ::profiler::block_index_t _parent_index)
: total_duration(_duration)
, min_duration_block(_block_index)
, max_duration_block(_block_index)
, parent_block(_parent_index)
, calls_number(1)
{
}
//BlockStatistics() = default;
inline ::profiler::timestamp_t average_duration() const
{
return total_duration / calls_number;
}
}; // END of struct BlockStatistics.
#pragma pack(pop)
extern "C" PROFILER_API void release_stats(BlockStatistics*& _stats);
//////////////////////////////////////////////////////////////////////////
class BlocksTree EASY_FINAL
{
typedef BlocksTree This;
public:
typedef ::std::vector<This> blocks_t;
typedef ::std::vector<::profiler::block_index_t> children_t;
children_t children; ///< List of children blocks. May be empty.
::profiler::SerializedBlock* node; ///< Pointer to serilized data (type, name, begin, end etc.)
::profiler::BlockStatistics* per_parent_stats; ///< Pointer to statistics for this block within the parent (may be nullptr for top-level blocks)
::profiler::BlockStatistics* per_frame_stats; ///< Pointer to statistics for this block within the frame (may be nullptr for top-level blocks)
::profiler::BlockStatistics* per_thread_stats; ///< Pointer to statistics for this block within the bounds of all frames per current thread
uint16_t depth; ///< Maximum number of sublevels (maximum children depth)
BlocksTree()
: node(nullptr)
, per_parent_stats(nullptr)
, per_frame_stats(nullptr)
, per_thread_stats(nullptr)
, depth(0)
{
}
BlocksTree(This&& that) : BlocksTree()
{
make_move(::std::forward<This&&>(that));
}
This& operator = (This&& that)
{
make_move(::std::forward<This&&>(that));
return *this;
}
~BlocksTree()
{
release_stats(per_thread_stats);
release_stats(per_parent_stats);
release_stats(per_frame_stats);
}
bool operator < (const This& other) const
{
if (!node || !other.node)
return false;
return node->begin() < other.node->begin();
}
void shrink_to_fit()
{
//for (auto& child : children)
// child.shrink_to_fit();
// shrink version 1:
//children.shrink_to_fit();
// shrink version 2:
//children_t new_children;
//new_children.reserve(children.size());
//::std::move(children.begin(), children.end(), ::std::back_inserter(new_children));
//new_children.swap(children);
}
private:
BlocksTree(const This&) = delete;
This& operator = (const This&) = delete;
void make_move(This&& that)
{
if (per_thread_stats != that.per_thread_stats)
release_stats(per_thread_stats);
if (per_parent_stats != that.per_parent_stats)
release_stats(per_parent_stats);
if (per_frame_stats != that.per_frame_stats)
release_stats(per_frame_stats);
children = ::std::move(that.children);
node = that.node;
per_parent_stats = that.per_parent_stats;
per_frame_stats = that.per_frame_stats;
per_thread_stats = that.per_thread_stats;
depth = that.depth;
that.node = nullptr;
that.per_parent_stats = nullptr;
that.per_frame_stats = nullptr;
that.per_thread_stats = nullptr;
}
}; // END of class BlocksTree.
//////////////////////////////////////////////////////////////////////////
class BlocksTreeRoot EASY_FINAL
{
typedef BlocksTreeRoot This;
public:
BlocksTree::children_t children; ///< List of children indexes
BlocksTree::children_t sync; ///< List of context-switch events
BlocksTree::children_t events; ///< List of events indexes
std::string thread_name; ///< Name of this thread
::profiler::timestamp_t profiled_time; ///< Profiled time of this thread (sum of all children duration)
::profiler::timestamp_t wait_time; ///< Wait time of this thread (sum of all context switches)
::profiler::thread_id_t thread_id; ///< System Id of this thread
::profiler::block_index_t blocks_number; ///< Total blocks number including their children
uint16_t depth; ///< Maximum stack depth (number of levels)
BlocksTreeRoot() : profiled_time(0), wait_time(0), thread_id(0), blocks_number(0), depth(0)
{
}
BlocksTreeRoot(This&& that)
: children(::std::move(that.children))
, sync(::std::move(that.sync))
, events(::std::move(that.events))
, thread_name(::std::move(that.thread_name))
, profiled_time(that.profiled_time)
, wait_time(that.wait_time)
, thread_id(that.thread_id)
, blocks_number(that.blocks_number)
, depth(that.depth)
{
}
This& operator = (This&& that)
{
children = ::std::move(that.children);
sync = ::std::move(that.sync);
events = ::std::move(that.events);
thread_name = ::std::move(that.thread_name);
profiled_time = that.profiled_time;
wait_time = that.wait_time;
thread_id = that.thread_id;
blocks_number = that.blocks_number;
depth = that.depth;
return *this;
}
inline bool got_name() const
{
return !thread_name.empty();
}
inline const char* name() const
{
return thread_name.c_str();
}
bool operator < (const This& other) const
{
return thread_id < other.thread_id;
}
private:
BlocksTreeRoot(const This&) = delete;
This& operator = (const This&) = delete;
}; // END of class BlocksTreeRoot.
typedef ::profiler::BlocksTree::blocks_t blocks_t;
typedef ::std::unordered_map<::profiler::thread_id_t, ::profiler::BlocksTreeRoot, ::profiler::passthrough_hash> thread_blocks_tree_t;
//////////////////////////////////////////////////////////////////////////
class PROFILER_API SerializedData EASY_FINAL
{
char* m_data;
size_t m_size;
public:
SerializedData() : m_data(nullptr), m_size(0)
{
}
SerializedData(SerializedData&& that) : m_data(that.m_data), m_size(that.m_size)
{
that.m_data = nullptr;
that.m_size = 0;
}
~SerializedData()
{
clear();
}
void set(uint64_t _size);
void extend(uint64_t _size);
SerializedData& operator = (SerializedData&& that)
{
set(that.m_data, that.m_size);
that.m_data = nullptr;
that.m_size = 0;
return *this;
}
char* operator [] (uint64_t i)
{
return m_data + i;
}
const char* operator [] (uint64_t i) const
{
return m_data + i;
}
bool empty() const
{
return m_size == 0;
}
uint64_t size() const
{
return m_size;
}
char* data()
{
return m_data;
}
const char* data() const
{
return m_data;
}
void clear()
{
set(nullptr, 0);
}
void swap(SerializedData& other)
{
char* d = other.m_data;
uint64_t sz = other.m_size;
other.m_data = m_data;
other.m_size = m_size;
m_data = d;
m_size = sz;
}
private:
void set(char* _data, uint64_t _size);
SerializedData(const SerializedData&) = delete;
SerializedData& operator = (const SerializedData&) = delete;
}; // END of class SerializedData.
//////////////////////////////////////////////////////////////////////////
typedef ::std::vector<SerializedBlockDescriptor*> descriptors_list_t;
} // END of namespace profiler.
extern "C" {
PROFILER_API ::profiler::block_index_t fillTreesFromFile(::std::atomic<int>& progress, const char* filename,
::profiler::SerializedData& serialized_blocks,
::profiler::SerializedData& serialized_descriptors,
::profiler::descriptors_list_t& descriptors,
::profiler::blocks_t& _blocks,
::profiler::thread_blocks_tree_t& threaded_trees,
uint32_t& total_descriptors_number,
bool gather_statistics,
::std::stringstream& _log);
PROFILER_API ::profiler::block_index_t fillTreesFromStream(::std::atomic<int>& progress, ::std::stringstream& str,
::profiler::SerializedData& serialized_blocks,
::profiler::SerializedData& serialized_descriptors,
::profiler::descriptors_list_t& descriptors,
::profiler::blocks_t& _blocks,
::profiler::thread_blocks_tree_t& threaded_trees,
uint32_t& total_descriptors_number,
bool gather_statistics,
::std::stringstream& _log);
PROFILER_API bool readDescriptionsFromStream(::std::atomic<int>& progress, ::std::stringstream& str,
::profiler::SerializedData& serialized_descriptors,
::profiler::descriptors_list_t& descriptors,
::std::stringstream& _log);
}
inline ::profiler::block_index_t fillTreesFromFile(const char* filename, ::profiler::SerializedData& serialized_blocks,
::profiler::SerializedData& serialized_descriptors,
::profiler::descriptors_list_t& descriptors, ::profiler::blocks_t& _blocks,
::profiler::thread_blocks_tree_t& threaded_trees,
uint32_t& total_descriptors_number,
bool gather_statistics,
::std::stringstream& _log)
{
::std::atomic<int> progress = ATOMIC_VAR_INIT(0);
return fillTreesFromFile(progress, filename, serialized_blocks, serialized_descriptors, descriptors, _blocks, threaded_trees, total_descriptors_number, gather_statistics, _log);
}
inline bool readDescriptionsFromStream(::std::stringstream& str,
::profiler::SerializedData& serialized_descriptors,
::profiler::descriptors_list_t& descriptors,
::std::stringstream& _log)
{
::std::atomic<int> progress = ATOMIC_VAR_INIT(0);
return readDescriptionsFromStream(progress, str, serialized_descriptors, descriptors, _log);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#endif // PROFILER_READER____H

View File

@ -0,0 +1,102 @@
/**
Lightweight profiler library for c++
Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
GNU General Public License Usage
Alternatively, this file may be used under the terms of the GNU
General Public License as published by the Free Software Foundation,
either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program.If not, see <http://www.gnu.org/licenses/>.
**/
#ifndef EASY_PROFILER_SERIALIZED_BLOCK__H_______
#define EASY_PROFILER_SERIALIZED_BLOCK__H_______
#include "../../../easy_profiler/include/easy/profiler.h"
namespace profiler {
//////////////////////////////////////////////////////////////////////////
class PROFILER_API SerializedBlock EASY_FINAL : public BaseBlockData
{
friend ::ProfileManager;
friend ::ThreadStorage;
public:
inline const char* data() const { return reinterpret_cast<const char*>(this); }
inline const char* name() const { return data() + sizeof(BaseBlockData); }
private:
SerializedBlock(const ::profiler::Block& block, uint16_t name_length);
SerializedBlock(const SerializedBlock&) = delete;
SerializedBlock& operator = (const SerializedBlock&) = delete;
~SerializedBlock() = delete;
}; // END of SerializedBlock.
//////////////////////////////////////////////////////////////////////////
#pragma pack(push, 1)
class PROFILER_API SerializedBlockDescriptor EASY_FINAL : public BaseBlockDescriptor
{
uint16_t m_nameLength;
public:
inline const char* data() const {
return reinterpret_cast<const char*>(this);
}
inline const char* name() const {
static const auto shift = sizeof(BaseBlockDescriptor) + sizeof(decltype(m_nameLength));
return data() + shift;
}
inline const char* file() const {
return name() + m_nameLength;
}
inline void setStatus(EasyBlockStatus _status)
{
m_status = _status;
}
private:
SerializedBlockDescriptor(const SerializedBlockDescriptor&) = delete;
SerializedBlockDescriptor& operator = (const SerializedBlockDescriptor&) = delete;
~SerializedBlockDescriptor() = delete;
}; // END of SerializedBlockDescriptor.
#pragma pack(pop)
//////////////////////////////////////////////////////////////////////////
} // END of namespace profiler.
#endif // EASY_PROFILER_SERIALIZED_BLOCK__H_______

View File

@ -0,0 +1,80 @@
/************************************************************************
* file name : outstream.h
* ----------------- :
* creation time : 2016/09/11
* authors : Sergey Yagovtsev, Victor Zarubkin
* emails : yse.sey@gmail.com, v.s.zarubkin@gmail.com
* ----------------- :
* description : The file contains definition of output stream helpers.
* ----------------- :
* change log : * 2016/09/11 Victor Zarubkin: Initial commit. Moved sources from profiler_manager.h/.cpp
* :
* : *
* ----------------- :
* license : Lightweight profiler library for c++
* : Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
* :
* : This program is free software : you can redistribute it and / or modify
* : it under the terms of the GNU General Public License as published by
* : the Free Software Foundation, either version 3 of the License, or
* : (at your option) any later version.
* :
* : This program is distributed in the hope that it will be useful,
* : but WITHOUT ANY WARRANTY; without even the implied warranty of
* : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
* : GNU General Public License for more details.
* :
* : You should have received a copy of the GNU General Public License
* : along with this program.If not, see <http://www.gnu.org/licenses/>.
************************************************************************/
#ifndef EASY_PROFILER__OUTPUT_STREAM__H_
#define EASY_PROFILER__OUTPUT_STREAM__H_
#include <sstream>
#include <string.h>
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
namespace profiler {
class OStream
{
::std::stringstream m_stream;
public:
explicit OStream() : m_stream(std::ios_base::out | std::ios_base::binary)
{
}
template <typename T> void write(const char* _data, T _size)
{
m_stream.write(_data, _size);
}
template <class T> void write(const T& _data)
{
m_stream.write((const char*)&_data, sizeof(T));
}
::std::stringstream& stream()
{
return m_stream;
}
const ::std::stringstream& stream() const
{
return m_stream;
}
}; // END of class OStream.
} // END of namespace profiler.
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
#endif // EASY_PROFILER__OUTPUT_STREAM__H_

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,456 @@
/**
Lightweight profiler library for c++
Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
GNU General Public License Usage
Alternatively, this file may be used under the terms of the GNU
General Public License as published by the Free Software Foundation,
either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program.If not, see <http://www.gnu.org/licenses/>.
**/
#ifndef EASY_PROFILER____MANAGER____H______
#define EASY_PROFILER____MANAGER____H______
#include <map>
#include <vector>
#include <unordered_map>
#include <thread>
#include <atomic>
#include "../easy_profiler/hashed_cstr.h"
#include "../easy_profiler/include/easy/easy_socket.h"
#include "../easy_profiler/include/easy/profiler.h"
#include "../easy_profiler/outstream.h"
#include "../easy_profiler/spin_lock.h"
//#include <list>
//////////////////////////////////////////////////////////////////////////
#ifdef _WIN32
#include <Windows.h>
#else
#include <sys/types.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <chrono>
#include <time.h>
#endif
inline uint32_t getCurrentThreadId()
{
#ifdef _WIN32
return (uint32_t)::GetCurrentThreadId();
#else
EASY_THREAD_LOCAL static const pid_t x = syscall(__NR_gettid);
EASY_THREAD_LOCAL static const uint32_t _id = (uint32_t)x;//std::hash<std::thread::id>()(std::this_thread::get_id());
return _id;
#endif
}
namespace profiler {
class SerializedBlock;
struct do_not_calc_hash {
template <class T> inline size_t operator()(T _value) const {
return static_cast<size_t>(_value);
}
};
}
//////////////////////////////////////////////////////////////////////////
#ifndef EASY_ENABLE_BLOCK_STATUS
# define EASY_ENABLE_BLOCK_STATUS 1
#endif
#ifndef EASY_ENABLE_ALIGNMENT
# define EASY_ENABLE_ALIGNMENT 0
#endif
#ifndef EASY_ALIGNMENT_SIZE
# define EASY_ALIGNMENT_SIZE 64
#endif
#if EASY_ENABLE_ALIGNMENT == 0
# define EASY_ALIGNED(TYPE, VAR, A) TYPE VAR
# define EASY_MALLOC(MEMSIZE, A) malloc(MEMSIZE)
# define EASY_FREE(MEMPTR) free(MEMPTR)
#else
# if defined(_MSC_VER)
# define EASY_ALIGNED(TYPE, VAR, A) __declspec(align(A)) TYPE VAR
# define EASY_MALLOC(MEMSIZE, A) _aligned_malloc(MEMSIZE, A)
# define EASY_FREE(MEMPTR) _aligned_free(MEMPTR)
# elif defined(__GNUC__)
# define EASY_ALIGNED(TYPE, VAR, A) TYPE VAR __attribute__(aligned(A))
# else
# define EASY_ALIGNED(TYPE, VAR, A) TYPE VAR
# endif
#endif
template <const uint16_t N>
class chunk_allocator
{
struct chunk { EASY_ALIGNED(int8_t, data[N], EASY_ALIGNMENT_SIZE); chunk* prev = nullptr; };
struct chunk_list
{
chunk* last = nullptr;
~chunk_list()
{
clear();
}
void clear()
{
do {
auto p = last;
last = last->prev;
EASY_FREE(p);
} while (last != nullptr);
}
chunk& back()
{
return *last;
}
void emplace_back()
{
auto prev = last;
last = ::new (EASY_MALLOC(sizeof(chunk), EASY_ALIGNMENT_SIZE)) chunk();
last->prev = prev;
*(uint16_t*)last->data = 0;
}
void invert()
{
chunk* next = nullptr;
while (last->prev != nullptr) {
auto p = last->prev;
last->prev = next;
next = last;
last = p;
}
last->prev = next;
}
};
//typedef std::list<chunk> chunk_list;
chunk_list m_chunks;
uint32_t m_size;
uint16_t m_shift;
public:
chunk_allocator() : m_size(0), m_shift(0)
{
m_chunks.emplace_back();
}
void* allocate(uint16_t n)
{
++m_size;
if (!need_expand(n))
{
int8_t* data = m_chunks.back().data + m_shift;
m_shift += n + sizeof(uint16_t);
*(uint16_t*)data = n;
data = data + sizeof(uint16_t);
if (m_shift + 1 < N)
*(uint16_t*)(data + n) = 0;
return data;
}
m_shift = n + sizeof(uint16_t);
m_chunks.emplace_back();
auto data = m_chunks.back().data;
*(uint16_t*)data = n;
data = data + sizeof(uint16_t);
*(uint16_t*)(data + n) = 0;
return data;
}
inline bool need_expand(uint16_t n) const
{
return (m_shift + n + sizeof(uint16_t)) > N;
}
inline uint32_t size() const
{
return m_size;
}
inline bool empty() const
{
return m_size == 0;
}
void clear()
{
m_size = 0;
m_shift = 0;
m_chunks.clear();
m_chunks.emplace_back();
}
/** Serialize data to stream.
\warning Data will be cleared after serialization.
*/
void serialize(profiler::OStream& _outputStream)
{
m_chunks.invert();
auto current = m_chunks.last;
do {
const int8_t* data = current->data;
uint16_t i = 0;
while (i + 1 < N && *(uint16_t*)data != 0) {
const uint16_t size = sizeof(uint16_t) + *(uint16_t*)data;
_outputStream.write((const char*)data, size);
data = data + size;
i += size;
}
current = current->prev;
} while (current != nullptr);
clear();
}
};
//////////////////////////////////////////////////////////////////////////
const uint16_t SIZEOF_CSWITCH = sizeof(profiler::BaseBlockData) + 1 + sizeof(uint16_t);
typedef std::vector<profiler::SerializedBlock*> serialized_list_t;
template <class T, const uint16_t N>
struct BlocksList
{
BlocksList() = default;
class Stack {
//std::stack<T> m_stack;
std::vector<T> m_stack;
public:
inline void clear() { m_stack.clear(); }
inline bool empty() const { return m_stack.empty(); }
inline void emplace(profiler::Block& _block) {
//m_stack.emplace(_block);
m_stack.emplace_back(_block);
}
inline void emplace(profiler::Block&& _block) {
//m_stack.emplace(_block);
m_stack.emplace_back(std::forward<profiler::Block&&>(_block));
}
template <class ... TArgs> inline void emplace(TArgs ... _args) {
//m_stack.emplace(_args);
m_stack.emplace_back(_args...);
}
inline T& top() {
//return m_stack.top();
return m_stack.back();
}
inline void pop() {
//m_stack.pop();
m_stack.pop_back();
}
};
Stack openedList;
chunk_allocator<N> closedList;
uint64_t usedMemorySize = 0;
void clearClosed() {
//closedList.clear();
usedMemorySize = 0;
}
};
struct ThreadStorage
{
BlocksList<std::reference_wrapper<profiler::Block>, SIZEOF_CSWITCH * (uint16_t)128U> blocks;
BlocksList<profiler::Block, SIZEOF_CSWITCH * (uint16_t)128U> sync;
std::string name;
#ifndef _WIN32
const pthread_t pthread_id;
#endif
const profiler::thread_id_t id;
std::atomic<char> expired;
std::atomic_bool frame; ///< is new frame working
bool allowChildren;
bool named;
bool guarded;
void storeBlock(const profiler::Block& _block);
void storeCSwitch(const profiler::Block& _block);
void clearClosed();
ThreadStorage();
};
//////////////////////////////////////////////////////////////////////////
typedef uint32_t processid_t;
class BlockDescriptor;
class ProfileManager
{
#ifndef EASY_MAGIC_STATIC_CPP11
friend class ProfileManagerInstance;
#endif
ProfileManager();
ProfileManager(const ProfileManager& p) = delete;
ProfileManager& operator=(const ProfileManager&) = delete;
typedef profiler::guard_lock<profiler::spin_lock> guard_lock_t;
typedef std::map<profiler::thread_id_t, ThreadStorage> map_of_threads_stacks;
typedef std::vector<BlockDescriptor*> block_descriptors_t;
#ifdef EASY_PROFILER_HASHED_CSTR_DEFINED
typedef std::unordered_map<profiler::hashed_cstr, profiler::block_id_t> descriptors_map_t;
#else
typedef std::unordered_map<profiler::hashed_stdstring, profiler::block_id_t> descriptors_map_t;
#endif
const processid_t m_processId;
map_of_threads_stacks m_threads;
block_descriptors_t m_descriptors;
descriptors_map_t m_descriptorsMap;
uint64_t m_usedMemorySize;
profiler::timestamp_t m_beginTime;
profiler::timestamp_t m_endTime;
profiler::spin_lock m_spin;
profiler::spin_lock m_storedSpin;
profiler::spin_lock m_dumpSpin;
std::atomic<char> m_profilerStatus;
std::atomic_bool m_isEventTracingEnabled;
std::atomic_bool m_isAlreadyListening;
std::string m_csInfoFilename = "/tmp/cs_profiling_info.log";
uint32_t dumpBlocksToStream(profiler::OStream& _outputStream, bool _lockSpin);
void setBlockStatus(profiler::block_id_t _id, profiler::EasyBlockStatus _status);
std::thread m_listenThread;
void listen(uint16_t _port);
std::atomic_bool m_stopListen;
public:
static ProfileManager& instance();
~ProfileManager();
const profiler::BaseBlockDescriptor* addBlockDescriptor(profiler::EasyBlockStatus _defaultStatus,
const char* _autogenUniqueId,
const char* _name,
const char* _filename,
int _line,
profiler::block_type_t _block_type,
profiler::color_t _color,
bool _copyName = false);
bool storeBlock(const profiler::BaseBlockDescriptor* _desc, const char* _runtimeName);
void beginBlock(profiler::Block& _block);
void endBlock();
void setEnabled(bool isEnable);
bool isEnabled() const;
void setEventTracingEnabled(bool _isEnable);
bool isEventTracingEnabled() const;
uint32_t dumpBlocksToFile(const char* filename);
const char* registerThread(const char* name, profiler::ThreadGuard& threadGuard);
const char* registerThread(const char* name);
void setContextSwitchLogFilename(const char* name)
{
m_csInfoFilename = name;
}
const char* getContextSwitchLogFilename() const
{
return m_csInfoFilename.c_str();
}
void beginContextSwitch(profiler::thread_id_t _thread_id, profiler::timestamp_t _time, profiler::thread_id_t _target_thread_id, const char* _target_process, bool _lockSpin = true);
void endContextSwitch(profiler::thread_id_t _thread_id, processid_t _process_id, profiler::timestamp_t _endtime, bool _lockSpin = true);
void startListen(uint16_t _port);
void stopListen();
bool isListening() const;
private:
void enableEventTracer();
void disableEventTracer();
char checkThreadExpired(ThreadStorage& _registeredThread);
void storeBlockForce(const profiler::BaseBlockDescriptor* _desc, const char* _runtimeName, ::profiler::timestamp_t& _timestamp);
void storeBlockForce2(const profiler::BaseBlockDescriptor* _desc, const char* _runtimeName, ::profiler::timestamp_t _timestamp);
void storeBlockForce2(ThreadStorage& _registeredThread, const profiler::BaseBlockDescriptor* _desc, const char* _runtimeName, ::profiler::timestamp_t _timestamp);
ThreadStorage& _threadStorage(profiler::thread_id_t _thread_id);
ThreadStorage* _findThreadStorage(profiler::thread_id_t _thread_id);
inline ThreadStorage& threadStorage(profiler::thread_id_t _thread_id)
{
guard_lock_t lock(m_spin);
return _threadStorage(_thread_id);
}
inline ThreadStorage* findThreadStorage(profiler::thread_id_t _thread_id)
{
guard_lock_t lock(m_spin);
return _findThreadStorage(_thread_id);
}
};
#endif // EASY_PROFILER____MANAGER____H______

View File

@ -0,0 +1,948 @@
/************************************************************************
* file name : reader.cpp
* ----------------- :
* creation time : 2016/06/19
* authors : Sergey Yagovtsev, Victor Zarubkin
* emails : yse.sey@gmail.com, v.s.zarubkin@gmail.com
* ----------------- :
* description : The file contains implementation of fillTreesFromFile function
* : which reads profiler file and fill profiler blocks tree.
* ----------------- :
* change log : * 2016/06/19 Sergey Yagovtsev: First fillTreesFromFile implementation.
* :
* : * 2016/06/25 Victor Zarubkin: Removed unnecessary memory allocation and copy
* : when creating and inserting blocks into the tree.
* :
* : * 2016/06/26 Victor Zarubkin: Added statistics gathering (min, max, average duration,
* : number of block calls).
* : * 2016/06/26 Victor Zarubkin, Sergey Yagovtsev: Added statistics gathering for root
* : blocks in the tree.
* :
* : * 2016/06/29 Victor Zarubkin: Added calculaton of total children number for blocks.
* :
* : * 2016/06/30 Victor Zarubkin: Added this header.
* : Added tree depth calculation.
* :
* : *
* ----------------- :
* license : Lightweight profiler library for c++
* : Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
* :
* :
* : Licensed under the Apache License, Version 2.0 (the "License");
* : you may not use this file except in compliance with the License.
* : You may obtain a copy of the License at
* :
* : http://www.apache.org/licenses/LICENSE-2.0
* :
* : Unless required by applicable law or agreed to in writing, software
* : distributed under the License is distributed on an "AS IS" BASIS,
* : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* : See the License for the specific language governing permissions and
* : limitations under the License.
* :
* :
* : GNU General Public License Usage
* : Alternatively, this file may be used under the terms of the GNU
* : General Public License as published by the Free Software Foundation,
* : either version 3 of the License, or (at your option) any later version.
* :
* : This program is distributed in the hope that it will be useful,
* : but WITHOUT ANY WARRANTY; without even the implied warranty of
* : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
* : GNU General Public License for more details.
* :
* : You should have received a copy of the GNU General Public License
* : along with this program.If not, see <http://www.gnu.org/licenses/>.
************************************************************************/
#include "../easy_profiler/include/easy/reader.h"
#include <fstream>
#include <sstream>
#include <iterator>
#include <algorithm>
#include <unordered_map>
#include <thread>
#include "../easy_profiler/hashed_cstr.h"
//////////////////////////////////////////////////////////////////////////
typedef uint32_t processid_t;
extern const uint32_t PROFILER_SIGNATURE;
extern const uint32_t EASY_CURRENT_VERSION;
# define EASY_VERSION_INT(v_major, v_minor, v_patch) ((static_cast<uint32_t>(v_major) << 24) | (static_cast<uint32_t>(v_minor) << 16) | static_cast<uint32_t>(v_patch))
const uint32_t MIN_COMPATIBLE_VERSION = EASY_VERSION_INT(0, 1, 0); ///< minimal compatible version (.prof file format was not changed seriously since this version)
const uint32_t EASY_V_100 = EASY_VERSION_INT(1, 0, 0); ///< in v1.0.0 some additional data were added into .prof file
# undef EASY_VERSION_INT
const uint64_t TIME_FACTOR = 1000000000ULL;
// TODO: use 128 bit integer operations for better accuracy
#define EASY_USE_FLOATING_POINT_CONVERSION
#ifdef EASY_USE_FLOATING_POINT_CONVERSION
// Suppress warnings about double to uint64 conversion
# ifdef _MSC_VER
# pragma warning(disable:4244)
# elif defined(__GNUC__)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wconversion"
# pragma GCC diagnostic ignored "-Wsign-conversion"
# elif defined(__clang__)
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wconversion"
# pragma clang diagnostic ignored "-Wsign-conversion"
# endif
# define EASY_CONVERT_TO_NANO(t, freq, factor) t *= factor
#else
# define EASY_CONVERT_TO_NANO(t, freq, factor) t *= TIME_FACTOR; t /= freq
#endif
//////////////////////////////////////////////////////////////////////////
inline bool isCompatibleVersion(uint32_t _version)
{
return _version >= MIN_COMPATIBLE_VERSION;
}
inline void write(::std::stringstream& _stream, const char* _value, size_t _size)
{
_stream.write(_value, _size);
}
template <class T>
inline void write(::std::stringstream& _stream, const T& _value)
{
_stream.write((const char*)&_value, sizeof(T));
}
//////////////////////////////////////////////////////////////////////////
namespace profiler {
void SerializedData::set(char* _data, uint64_t _size)
{
delete [] m_data;
m_data = _data;
m_size = _size;
}
void SerializedData::set(uint64_t _size)
{
if (_size != 0)
set(new char[_size], _size);
else
set(nullptr, 0);
}
void SerializedData::extend(uint64_t _size)
{
auto olddata = m_data;
auto oldsize = m_size;
m_size = oldsize + _size;
m_data = new char[m_size];
if (olddata != nullptr) {
memcpy(m_data, olddata, oldsize);
delete [] olddata;
}
}
extern "C" PROFILER_API void release_stats(BlockStatistics*& _stats)
{
if (_stats == nullptr)
return;
if (--_stats->calls_number == 0)
delete _stats;
_stats = nullptr;
}
}
//////////////////////////////////////////////////////////////////////////
#ifdef EASY_PROFILER_HASHED_CSTR_DEFINED
typedef ::std::unordered_map<::profiler::block_id_t, ::profiler::BlockStatistics*, ::profiler::passthrough_hash> StatsMap;
/** \note It is absolutely safe to use hashed_cstr (which simply stores pointer) because std::unordered_map,
which uses it as a key, exists only inside fillTreesFromFile function. */
typedef ::std::unordered_map<::profiler::hashed_cstr, ::profiler::block_id_t> IdMap;
typedef ::std::unordered_map<::profiler::hashed_cstr, ::profiler::BlockStatistics*> CsStatsMap;
#else
// TODO: Create optimized version of profiler::hashed_cstr for Linux too.
typedef ::std::unordered_map<::profiler::block_id_t, ::profiler::BlockStatistics*, ::profiler::passthrough_hash> StatsMap;
typedef ::std::unordered_map<::profiler::hashed_stdstring, ::profiler::block_id_t> IdMap;
typedef ::std::unordered_map<::profiler::hashed_stdstring, ::profiler::BlockStatistics*> CsStatsMap;
#endif
//////////////////////////////////////////////////////////////////////////
/** \brief Updates statistics for a profiler block.
\param _stats_map Storage of statistics for blocks.
\param _current Pointer to the current block.
\param _stats Reference to the variable where pointer to the block statistics must be written.
\note All blocks with similar name have the same pointer to statistics information.
\note As all profiler block keeps a pointer to it's statistics, all similar blocks
automatically receive statistics update.
*/
::profiler::BlockStatistics* update_statistics(StatsMap& _stats_map, const ::profiler::BlocksTree& _current, ::profiler::block_index_t _current_index, ::profiler::block_index_t _parent_index, const ::profiler::blocks_t& _blocks)
{
auto duration = _current.node->duration();
//StatsMap::key_type key(_current.node->name());
//auto it = _stats_map.find(key);
auto it = _stats_map.find(_current.node->id());
if (it != _stats_map.end())
{
// Update already existing statistics
auto stats = it->second; // write pointer to statistics into output (this is BlocksTree:: per_thread_stats or per_parent_stats or per_frame_stats)
++stats->calls_number; // update calls number of this block
stats->total_duration += duration; // update summary duration of all block calls
if (duration > _blocks[stats->max_duration_block].node->duration())
{
// update max duration
stats->max_duration_block = _current_index;
//stats->max_duration = duration;
}
if (duration < _blocks[stats->min_duration_block].node->duration())
{
// update min duraton
stats->min_duration_block = _current_index;
//stats->min_duration = duration;
}
// average duration is calculated inside average_duration() method by dividing total_duration to the calls_number
return stats;
}
// This is first time the block appear in the file.
// Create new statistics.
auto stats = new ::profiler::BlockStatistics(duration, _current_index, _parent_index);
//_stats_map.emplace(key, stats);
_stats_map.emplace(_current.node->id(), stats);
return stats;
}
::profiler::BlockStatistics* update_statistics(CsStatsMap& _stats_map, const ::profiler::BlocksTree& _current, ::profiler::block_index_t _current_index, ::profiler::block_index_t _parent_index, const ::profiler::blocks_t& _blocks)
{
auto duration = _current.node->duration();
CsStatsMap::key_type key(_current.node->name());
auto it = _stats_map.find(key);
if (it != _stats_map.end())
{
// Update already existing statistics
auto stats = it->second; // write pointer to statistics into output (this is BlocksTree:: per_thread_stats or per_parent_stats or per_frame_stats)
++stats->calls_number; // update calls number of this block
stats->total_duration += duration; // update summary duration of all block calls
if (duration > _blocks[stats->max_duration_block].node->duration())
{
// update max duration
stats->max_duration_block = _current_index;
//stats->max_duration = duration;
}
if (duration < _blocks[stats->min_duration_block].node->duration())
{
// update min duraton
stats->min_duration_block = _current_index;
//stats->min_duration = duration;
}
// average duration is calculated inside average_duration() method by dividing total_duration to the calls_number
return stats;
}
// This is first time the block appear in the file.
// Create new statistics.
auto stats = new ::profiler::BlockStatistics(duration, _current_index, _parent_index);
_stats_map.emplace(key, stats);
return stats;
}
//////////////////////////////////////////////////////////////////////////
void update_statistics_recursive(StatsMap& _stats_map, ::profiler::BlocksTree& _current, ::profiler::block_index_t _current_index, ::profiler::block_index_t _parent_index, ::profiler::blocks_t& _blocks)
{
_current.per_frame_stats = update_statistics(_stats_map, _current, _current_index, _parent_index, _blocks);
for (auto i : _current.children)
update_statistics_recursive(_stats_map, _blocks[i], i, _parent_index, _blocks);
}
//////////////////////////////////////////////////////////////////////////
/*void validate_pointers(::std::atomic<int>& _progress, const char* _oldbase, ::profiler::SerializedData& _serialized_blocks, ::profiler::blocks_t& _blocks, size_t _size)
{
if (_oldbase == nullptr)
{
_progress.store(25, ::std::memory_order_release);
return;
}
for (size_t i = 0; i < _size; ++i)
{
auto& tree = _blocks[i];
auto dist = ::std::distance(_oldbase, reinterpret_cast<const char*>(tree.node));
tree.node = reinterpret_cast<::profiler::SerializedBlock*>(_serialized_blocks.data() + dist);
_progress.store(20 + static_cast<int>(5 * i / _size), ::std::memory_order_release);
}
}
void validate_pointers(::std::atomic<int>& _progress, const char* _oldbase, ::profiler::SerializedData& _serialized_descriptors, ::profiler::descriptors_list_t& _descriptors, size_t _size)
{
if (_oldbase == nullptr)
{
_progress.store(5, ::std::memory_order_release);
return;
}
for (size_t i = 0; i < _size; ++i)
{
auto dist = ::std::distance(_oldbase, reinterpret_cast<const char*>(_descriptors[i]));
_descriptors[i] = reinterpret_cast<::profiler::SerializedBlockDescriptor*>(_serialized_descriptors.data() + dist);
_progress.store(static_cast<int>(5 * i / _size));
}
}*/
//////////////////////////////////////////////////////////////////////////
extern "C" {
PROFILER_API ::profiler::block_index_t fillTreesFromFile(::std::atomic<int>& progress, const char* filename,
::profiler::SerializedData& serialized_blocks,
::profiler::SerializedData& serialized_descriptors,
::profiler::descriptors_list_t& descriptors,
::profiler::blocks_t& blocks,
::profiler::thread_blocks_tree_t& threaded_trees,
uint32_t& total_descriptors_number,
bool gather_statistics,
::std::stringstream& _log)
{
auto oldprogress = progress.exchange(0, ::std::memory_order_release);
if (oldprogress < 0)
{
_log << "Reading was interrupted";
return 0;
}
::std::ifstream inFile(filename, ::std::fstream::binary);
if (!inFile.is_open())
{
_log << "Can not open file " << filename;
return 0;
}
::std::stringstream str;
// Replace str buffer to inFile buffer to avoid redundant copying
typedef ::std::basic_iostream<::std::stringstream::char_type, ::std::stringstream::traits_type> stringstream_parent;
stringstream_parent& s = str;
auto oldbuf = s.rdbuf(inFile.rdbuf());
// Read data from file
auto result = fillTreesFromStream(progress, str, serialized_blocks, serialized_descriptors, descriptors, blocks,
threaded_trees, total_descriptors_number, gather_statistics, _log);
// Restore old str buffer to avoid possible second memory free on stringstream destructor
s.rdbuf(oldbuf);
return result;
}
//////////////////////////////////////////////////////////////////////////
PROFILER_API ::profiler::block_index_t fillTreesFromStream(::std::atomic<int>& progress, ::std::stringstream& inFile,
::profiler::SerializedData& serialized_blocks,
::profiler::SerializedData& serialized_descriptors,
::profiler::descriptors_list_t& descriptors,
::profiler::blocks_t& blocks,
::profiler::thread_blocks_tree_t& threaded_trees,
uint32_t& total_descriptors_number,
bool gather_statistics,
::std::stringstream& _log)
{
EASY_FUNCTION(::profiler::colors::Cyan);
auto oldprogress = progress.exchange(0, ::std::memory_order_release);
if (oldprogress < 0)
{
_log << "Reading was interrupted";
return 0;
}
uint32_t signature = 0;
inFile.read((char*)&signature, sizeof(uint32_t));
if (signature != PROFILER_SIGNATURE)
{
_log << "Wrong signature " << signature << "\nThis is not EasyProfiler file/stream.";
return 0;
}
uint32_t version = 0;
inFile.read((char*)&version, sizeof(uint32_t));
if (!isCompatibleVersion(version))
{
_log << "Incompatible version: v" << (version >> 24) << "." << ((version & 0x00ff0000) >> 16) << "." << (version & 0x0000ffff);
return 0;
}
processid_t pid = 0;
if (version > EASY_V_100)
inFile.read((char*)&pid, sizeof(processid_t));
int64_t file_cpu_frequency = 0LL;
inFile.read((char*)&file_cpu_frequency, sizeof(int64_t));
uint64_t cpu_frequency = file_cpu_frequency;
const double conversion_factor = static_cast<double>(TIME_FACTOR) / static_cast<double>(cpu_frequency);
::profiler::timestamp_t begin_time = 0ULL;
::profiler::timestamp_t end_time = 0ULL;
inFile.read((char*)&begin_time, sizeof(::profiler::timestamp_t));
inFile.read((char*)&end_time, sizeof(::profiler::timestamp_t));
if (cpu_frequency != 0)
{
EASY_CONVERT_TO_NANO(begin_time, cpu_frequency, conversion_factor);
EASY_CONVERT_TO_NANO(end_time, cpu_frequency, conversion_factor);
}
uint32_t total_blocks_number = 0;
inFile.read((char*)&total_blocks_number, sizeof(uint32_t));
if (total_blocks_number == 0)
{
_log << "Profiled blocks number == 0";
return 0;
}
uint64_t memory_size = 0;
inFile.read((char*)&memory_size, sizeof(decltype(memory_size)));
if (memory_size == 0)
{
_log << "Wrong memory size == 0 for " << total_blocks_number << " blocks";
return 0;
}
total_descriptors_number = 0;
inFile.read((char*)&total_descriptors_number, sizeof(uint32_t));
if (total_descriptors_number == 0)
{
_log << "Blocks description number == 0";
return 0;
}
uint64_t descriptors_memory_size = 0;
inFile.read((char*)&descriptors_memory_size, sizeof(decltype(descriptors_memory_size)));
if (descriptors_memory_size == 0)
{
_log << "Wrong memory size == 0 for " << total_descriptors_number << " blocks descriptions";
return 0;
}
descriptors.reserve(total_descriptors_number);
//const char* olddata = append_regime ? serialized_descriptors.data() : nullptr;
serialized_descriptors.set(descriptors_memory_size);
//validate_pointers(progress, olddata, serialized_descriptors, descriptors, descriptors.size());
uint64_t i = 0;
while (!inFile.eof() && descriptors.size() < total_descriptors_number)
{
uint16_t sz = 0;
inFile.read((char*)&sz, sizeof(sz));
if (sz == 0)
{
descriptors.push_back(nullptr);
continue;
}
//if (i + sz > descriptors_memory_size) {
// printf("FILE CORRUPTED\n");
// return 0;
//}
char* data = serialized_descriptors[i];
inFile.read(data, sz);
auto descriptor = reinterpret_cast<::profiler::SerializedBlockDescriptor*>(data);
descriptors.push_back(descriptor);
i += sz;
auto oldprogress = progress.exchange(static_cast<int>(15 * i / descriptors_memory_size), ::std::memory_order_release);
if (oldprogress < 0)
{
_log << "Reading was interrupted";
return 0; // Loading interrupted
}
}
typedef ::std::unordered_map<::profiler::thread_id_t, StatsMap, ::profiler::passthrough_hash> PerThreadStats;
PerThreadStats parent_statistics, frame_statistics;
IdMap identification_table;
blocks.reserve(total_blocks_number);
//olddata = append_regime ? serialized_blocks.data() : nullptr;
serialized_blocks.set(memory_size);
//validate_pointers(progress, olddata, serialized_blocks, blocks, blocks.size());
i = 0;
uint32_t read_number = 0;
::profiler::block_index_t blocks_counter = 0;
::std::vector<char> name;
while (!inFile.eof() && read_number < total_blocks_number)
{
EASY_BLOCK("Read thread data", ::profiler::colors::DarkGreen);
::profiler::thread_id_t thread_id = 0;
inFile.read((char*)&thread_id, sizeof(decltype(thread_id)));
auto& root = threaded_trees[thread_id];
uint16_t name_size = 0;
inFile.read((char*)&name_size, sizeof(uint16_t));
if (name_size != 0)
{
name.resize(name_size);
inFile.read(name.data(), name_size);
root.thread_name = name.data();
}
CsStatsMap per_thread_statistics_cs;
uint32_t blocks_number_in_thread = 0;
inFile.read((char*)&blocks_number_in_thread, sizeof(decltype(blocks_number_in_thread)));
auto threshold = read_number + blocks_number_in_thread;
while (!inFile.eof() && read_number < threshold)
{
EASY_BLOCK("Read context switch", ::profiler::colors::Green);
++read_number;
uint16_t sz = 0;
inFile.read((char*)&sz, sizeof(sz));
if (sz == 0)
{
_log << "Bad CSwitch block size == 0";
return 0;
}
char* data = serialized_blocks[i];
inFile.read(data, sz);
i += sz;
auto baseData = reinterpret_cast<::profiler::SerializedBlock*>(data);
auto t_begin = reinterpret_cast<::profiler::timestamp_t*>(data);
auto t_end = t_begin + 1;
if (cpu_frequency != 0)
{
EASY_CONVERT_TO_NANO(*t_begin, cpu_frequency, conversion_factor);
EASY_CONVERT_TO_NANO(*t_end, cpu_frequency, conversion_factor);
}
if (*t_end > begin_time)
{
if (*t_begin < begin_time)
*t_begin = begin_time;
blocks.emplace_back();
::profiler::BlocksTree& tree = blocks.back();
tree.node = baseData;
const auto block_index = blocks_counter++;
root.wait_time += baseData->duration();
root.sync.emplace_back(block_index);
if (gather_statistics)
{
EASY_BLOCK("Gather per thread statistics", ::profiler::colors::Coral);
tree.per_thread_stats = update_statistics(per_thread_statistics_cs, tree, block_index, thread_id, blocks);
}
}
auto oldprogress = progress.exchange(20 + static_cast<int>(70 * i / memory_size), ::std::memory_order_release);
if (oldprogress < 0)
{
_log << "Reading was interrupted";
return 0; // Loading interrupted
}
}
if (inFile.eof())
break;
StatsMap per_thread_statistics;
blocks_number_in_thread = 0;
inFile.read((char*)&blocks_number_in_thread, sizeof(decltype(blocks_number_in_thread)));
threshold = read_number + blocks_number_in_thread;
while (!inFile.eof() && read_number < threshold)
{
EASY_BLOCK("Read block", ::profiler::colors::Green);
++read_number;
uint16_t sz = 0;
inFile.read((char*)&sz, sizeof(sz));
if (sz == 0)
{
_log << "Bad block size == 0";
return 0;
}
char* data = serialized_blocks[i];
inFile.read(data, sz);
i += sz;
auto baseData = reinterpret_cast<::profiler::SerializedBlock*>(data);
if (baseData->id() >= total_descriptors_number)
{
_log << "Bad block id == " << baseData->id();
return 0;
}
auto desc = descriptors[baseData->id()];
if (desc == nullptr)
{
_log << "Bad block id == " << baseData->id() << ". Description is null.";
return 0;
}
auto t_begin = reinterpret_cast<::profiler::timestamp_t*>(data);
auto t_end = t_begin + 1;
if (cpu_frequency != 0)
{
EASY_CONVERT_TO_NANO(*t_begin, cpu_frequency, conversion_factor);
EASY_CONVERT_TO_NANO(*t_end, cpu_frequency, conversion_factor);
}
if (*t_end >= begin_time)
{
if (*t_begin < begin_time)
*t_begin = begin_time;
blocks.emplace_back();
::profiler::BlocksTree& tree = blocks.back();
tree.node = baseData;
const auto block_index = blocks_counter++;
if (*tree.node->name() != 0)
{
// If block has runtime name then generate new id for such block.
// Blocks with the same name will have same id.
IdMap::key_type key(tree.node->name());
auto it = identification_table.find(key);
if (it != identification_table.end())
{
// There is already block with such name, use it's id
baseData->setId(it->second);
}
else
{
// There were no blocks with such name, generate new id and save it in the table for further usage.
auto id = static_cast<::profiler::block_id_t>(descriptors.size());
identification_table.emplace(key, id);
if (descriptors.capacity() == descriptors.size())
descriptors.reserve((descriptors.size() * 3) >> 1);
descriptors.push_back(descriptors[baseData->id()]);
baseData->setId(id);
}
}
if (!root.children.empty())
{
auto& back = blocks[root.children.back()];
auto t1 = back.node->end();
auto mt0 = tree.node->begin();
if (mt0 < t1)//parent - starts earlier than last ends
{
//auto lower = ::std::lower_bound(root.children.begin(), root.children.end(), tree);
/**/
EASY_BLOCK("Find children", ::profiler::colors::Blue);
auto rlower1 = ++root.children.rbegin();
for (; rlower1 != root.children.rend() && !(mt0 > blocks[*rlower1].node->begin()); ++rlower1);
auto lower = rlower1.base();
::std::move(lower, root.children.end(), ::std::back_inserter(tree.children));
root.children.erase(lower, root.children.end());
EASY_END_BLOCK;
if (gather_statistics)
{
EASY_BLOCK("Gather statistic within parent", ::profiler::colors::Magenta);
auto& per_parent_statistics = parent_statistics[thread_id];
per_parent_statistics.clear();
//per_parent_statistics.reserve(tree.children.size()); // this gives slow-down on Windows
//per_parent_statistics.reserve(tree.children.size() * 2); // this gives no speed-up on Windows
// TODO: check this behavior on Linux
for (auto i : tree.children)
{
auto& child = blocks[i];
child.per_parent_stats = update_statistics(per_parent_statistics, child, i, block_index, blocks);
if (tree.depth < child.depth)
tree.depth = child.depth;
}
}
else
{
for (auto i : tree.children)
{
const auto& child = blocks[i];
if (tree.depth < child.depth)
tree.depth = child.depth;
}
}
++tree.depth;
}
}
++root.blocks_number;
root.children.emplace_back(block_index);// ::std::move(tree));
if (desc->type() == ::profiler::BLOCK_TYPE_EVENT)
root.events.emplace_back(block_index);
if (gather_statistics)
{
EASY_BLOCK("Gather per thread statistics", ::profiler::colors::Coral);
tree.per_thread_stats = update_statistics(per_thread_statistics, tree, block_index, thread_id, blocks);
}
}
auto oldprogress = progress.exchange(20 + static_cast<int>(70 * i / memory_size), ::std::memory_order_release);
if (oldprogress < 0)
{
_log << "Reading was interrupted";
return 0; // Loading interrupted
}
}
}
if (progress.load(::std::memory_order_acquire) < 0)
{
_log << "Reading was interrupted";
return 0; // Loading interrupted
}
EASY_BLOCK("Gather statistics for roots", ::profiler::colors::Purple);
if (gather_statistics)
{
::std::vector<::std::thread> statistics_threads;
statistics_threads.reserve(threaded_trees.size());
for (auto& it : threaded_trees)
{
auto& root = it.second;
root.thread_id = it.first;
//root.tree.shrink_to_fit();
auto& per_frame_statistics = frame_statistics[root.thread_id];
auto& per_parent_statistics = parent_statistics[it.first];
per_parent_statistics.clear();
statistics_threads.emplace_back(::std::thread([&per_parent_statistics, &per_frame_statistics, &blocks](::profiler::BlocksTreeRoot& root)
{
//::std::sort(root.sync.begin(), root.sync.end(), [&blocks](::profiler::block_index_t left, ::profiler::block_index_t right)
//{
// return blocks[left].node->begin() < blocks[right].node->begin();
//});
::profiler::block_index_t cs_index = 0;
for (auto i : root.children)
{
auto& frame = blocks[i];
frame.per_parent_stats = update_statistics(per_parent_statistics, frame, i, root.thread_id, blocks);
per_frame_statistics.clear();
update_statistics_recursive(per_frame_statistics, frame, i, i, blocks);
if (cs_index < root.sync.size())
{
CsStatsMap frame_stats_cs;
do {
auto j = root.sync[cs_index];
auto& cs = blocks[j];
if (cs.node->end() < frame.node->begin())
continue;
if (cs.node->begin() > frame.node->end())
break;
cs.per_frame_stats = update_statistics(frame_stats_cs, cs, cs_index, i, blocks);
} while (++cs_index < root.sync.size());
}
if (root.depth < frame.depth)
root.depth = frame.depth;
root.profiled_time += frame.node->duration();
}
++root.depth;
}, ::std::ref(root)));
}
int j = 0, n = static_cast<int>(statistics_threads.size());
for (auto& t : statistics_threads)
{
t.join();
progress.store(90 + (10 * ++j) / n, ::std::memory_order_release);
}
}
else
{
int j = 0, n = static_cast<int>(threaded_trees.size());
for (auto& it : threaded_trees)
{
auto& root = it.second;
root.thread_id = it.first;
//::std::sort(root.sync.begin(), root.sync.end(), [&blocks](::profiler::block_index_t left, ::profiler::block_index_t right)
//{
// return blocks[left].node->begin() < blocks[right].node->begin();
//});
//root.tree.shrink_to_fit();
for (auto i : root.children)
{
auto& frame = blocks[i];
if (root.depth < frame.depth)
root.depth = frame.depth;
root.profiled_time += frame.node->duration();
}
++root.depth;
progress.store(90 + (10 * ++j) / n, ::std::memory_order_release);
}
}
// No need to delete BlockStatistics instances - they will be deleted inside BlocksTree destructors
return blocks_counter;
}
//////////////////////////////////////////////////////////////////////////
PROFILER_API bool readDescriptionsFromStream(::std::atomic<int>& progress, ::std::stringstream& inFile,
::profiler::SerializedData& serialized_descriptors,
::profiler::descriptors_list_t& descriptors,
::std::stringstream& _log)
{
EASY_FUNCTION(::profiler::colors::Cyan);
progress.store(0);
uint32_t signature = 0;
inFile.read((char*)&signature, sizeof(uint32_t));
if (signature != PROFILER_SIGNATURE)
{
_log << "Wrong file signature.\nThis is not EasyProfiler file/stream.";
return false;
}
uint32_t version = 0;
inFile.read((char*)&version, sizeof(uint32_t));
if (!isCompatibleVersion(version))
{
_log << "Incompatible version: v" << (version >> 24) << "." << ((version & 0x00ff0000) >> 16) << "." << (version & 0x0000ffff);
return false;
}
uint32_t total_descriptors_number = 0;
inFile.read((char*)&total_descriptors_number, sizeof(decltype(total_descriptors_number)));
if (total_descriptors_number == 0)
{
_log << "Blocks description number == 0";
return false;
}
uint64_t descriptors_memory_size = 0;
inFile.read((char*)&descriptors_memory_size, sizeof(decltype(descriptors_memory_size)));
if (descriptors_memory_size == 0)
{
_log << "Wrong memory size == 0 for " << total_descriptors_number << " blocks descriptions";
return false;
}
descriptors.reserve(total_descriptors_number);
//const char* olddata = append_regime ? serialized_descriptors.data() : nullptr;
serialized_descriptors.set(descriptors_memory_size);
//validate_pointers(progress, olddata, serialized_descriptors, descriptors, descriptors.size());
uint64_t i = 0;
while (!inFile.eof() && descriptors.size() < total_descriptors_number)
{
uint16_t sz = 0;
inFile.read((char*)&sz, sizeof(sz));
if (sz == 0)
{
descriptors.push_back(nullptr);
continue;
}
//if (i + sz > descriptors_memory_size) {
// printf("FILE CORRUPTED\n");
// return 0;
//}
char* data = serialized_descriptors[i];
inFile.read(data, sz);
auto descriptor = reinterpret_cast<::profiler::SerializedBlockDescriptor*>(data);
descriptors.push_back(descriptor);
i += sz;
auto oldprogress = progress.exchange(static_cast<int>(100 * i / descriptors_memory_size), ::std::memory_order_release);
if (oldprogress < 0)
{
_log << "Reading was interrupted";
return false; // Loading interrupted
}
}
return !descriptors.empty();
}
//////////////////////////////////////////////////////////////////////////
}
#undef EASY_CONVERT_TO_NANO
#ifdef EASY_USE_FLOATING_POINT_CONVERSION
# ifdef _MSC_VER
# pragma warning(default:4244)
# elif defined(__GNUC__)
# pragma GCC diagnostic pop
# elif defined(__clang__)
# pragma clang diagnostic pop
# endif
# undef EASY_USE_FLOATING_POINT_CONVERSION
#endif

View File

@ -0,0 +1,30 @@
1 VERSIONINFO
# define EASY_STRINGIFY(a) #a
# define EASY_STRINGIFICATION(a) EASY_STRINGIFY(a)
#define EASY_PROFILER_PRODUCT_VERSION "v" EASY_STRINGIFICATION(EASY_PROFILER_VERSION_MAJOR) "." \
EASY_STRINGIFICATION(EASY_PROFILER_VERSION_MINOR) "." \
EASY_STRINGIFICATION(EASY_PROFILER_VERSION_PATCH)
FILEVERSION EASY_PROFILER_VERSION_MAJOR, EASY_PROFILER_VERSION_MINOR, EASY_PROFILER_VERSION_PATCH
PRODUCTVERSION EASY_PROFILER_VERSION_MAJOR, EASY_PROFILER_VERSION_MINOR, EASY_PROFILER_VERSION_PATCH
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "080904b0"
BEGIN
VALUE "CompanyName", "EasySolutions"
VALUE "FileDescription", "Lightweight profiler library for c++"
VALUE "LegalCopyright", "Copyright (C) 2016 Victor Zarubkin, Sergey Yagovtsev"
VALUE "LegalTrademarks1", "All Rights Reserved"
VALUE "LegalTrademarks2", "All Rights Reserved"
VALUE "ProductName", "easy_profiler lib"
VALUE "ProductVersion", EASY_PROFILER_PRODUCT_VERSION
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x809, 1200
END
END

View File

@ -0,0 +1,116 @@
/**
Lightweight profiler library for c++
Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
GNU General Public License Usage
Alternatively, this file may be used under the terms of the GNU
General Public License as published by the Free Software Foundation,
either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program.If not, see <http://www.gnu.org/licenses/>.
**/
#ifndef EASY_PROFILER__SPIN_LOCK__________H______
#define EASY_PROFILER__SPIN_LOCK__________H______
#define EASY_USE_CRITICAL_SECTION // Use CRITICAL_SECTION instead of std::atomic_flag
#if defined(_WIN32) && defined(EASY_USE_CRITICAL_SECTION)
#include <Windows.h>
#else
#include <atomic>
#endif
namespace profiler {
#if defined(_WIN32) && defined(EASY_USE_CRITICAL_SECTION)
// std::atomic_flag on Windows works slower than critical section, so we will use it instead of std::atomic_flag...
// By the way, Windows critical sections are slower than std::atomic_flag on Unix.
class spin_lock { CRITICAL_SECTION m_lock; public:
void lock() {
EnterCriticalSection(&m_lock);
}
void unlock() {
LeaveCriticalSection(&m_lock);
}
spin_lock() {
InitializeCriticalSection(&m_lock);
}
~spin_lock() {
DeleteCriticalSection(&m_lock);
}
};
#else
// std::atomic_flag on Unix works fine and very fast (almost instant!)
class spin_lock { ::std::atomic_flag m_lock; public:
void lock() {
while (m_lock.test_and_set(::std::memory_order_acquire));
}
void unlock() {
m_lock.clear(::std::memory_order_release);
}
spin_lock() {
m_lock.clear();
}
};
#endif
template <class T>
class guard_lock
{
T& m_lock;
bool m_isLocked = false;
public:
explicit guard_lock(T& m) : m_lock(m) {
m_lock.lock();
m_isLocked = true;
}
~guard_lock() {
unlock();
}
inline void unlock() {
if (m_isLocked) {
m_lock.unlock();
m_isLocked = false;
}
}
};
} // END of namespace profiler.
#ifdef EASY_USE_CRITICAL_SECTION
# undef EASY_USE_CRITICAL_SECTION
#endif
#endif // EASY_PROFILER__SPIN_LOCK__________H______

View File

@ -0,0 +1 @@
1.0.3

View File

@ -42,7 +42,7 @@ set(SRCS
)
set(LIB core)
add_library(${LIB} ${SRCS})
target_link_libraries(${LIB} io glm zlib ${CMAKE_DL_LIBS})
target_link_libraries(${LIB} io glm zlib easy_profiler ${CMAKE_DL_LIBS})
set_target_properties(${LIB} PROPERTIES FOLDER ${LIB})
gtest_suite_files(tests

View File

@ -18,6 +18,11 @@
#include "core/command/CommandHandler.h"
#endif
#define EASY_PROFILER_ENABLED 1
#if EASY_PROFILER_ENABLED
#include <easy/profiler.h>
#endif
#define MICROPROFILE_EMABLED 0
#if MICROPROFILE_EMABLED
#define MICROPROFILE_IMPL
@ -66,6 +71,8 @@ Trace::Trace(uint16_t port) {
MicroProfileSetEnableAllGroups(true);
MicroProfileSetForceMetaCounters(true);
MicroProfileStartContextSwitchTrace();
#elif EASY_PROFILER_ENABLED
profiler::startListen(port);
#endif
traceThread("MainThread");
}
@ -79,6 +86,8 @@ Trace::~Trace() {
}
#elif USE_EMTRACE
emscripten_trace_close();
#elif EASY_PROFILER_ENABLED
profiler::stopListen();
#elif MICROPROFILE_EMABLED
MicroProfileShutdown();
#endif
@ -109,6 +118,8 @@ void traceInit() {
Log::info("emtrace active");
#elif MICROPROFILE_ENABLED
Log::info("microprofile active on port " CORE_STRINGIFY(MICROPROFILE_WEBSERVER_PORT));
#elif EASY_PROFILER_ENABLED
EASY_PROFILER_ENABLE;
#endif
}
@ -123,6 +134,9 @@ void traceGLInit() {
}
void traceShutdown() {
#if EASY_PROFILER_ENABLED
EASY_PROFILER_DISABLE;
#endif
}
void traceGLShutdown() {
@ -174,6 +188,8 @@ void traceBegin(const char* name) {
_rmt_BeginCPUSample(name, 0, nullptr);
#elif USE_EMTRACE
emscripten_trace_enter_context(name);
#elif EASY_PROFILER_ENABLED
EASY_BLOCK(name);
#elif MICROPROFILE_EMABLED
MicroProfileEnter(getToken(MicroProfileTokenTypeCpu, name));
#endif
@ -182,6 +198,8 @@ void traceBegin(const char* name) {
void traceEnd() {
#if RMT_ENABLED
rmt_EndCPUSample();
#elif EASY_PROFILER_ENABLED
EASY_END_BLOCK;
#elif USE_EMTRACE
emscripten_trace_exit_context();
#elif MICROPROFILE_EMABLED
@ -228,6 +246,8 @@ void traceThread(const char* name) {
#elif MICROPROFILE_EMABLED
_threadName = name;
MicroProfileOnThreadCreate(name);
#elif EASY_PROFILER_ENABLED
EASY_THREAD(name);
#else
traceMessage(name);
#endif

View File

@ -5,6 +5,7 @@ add_subdirectory(glslang)
if (TOOLS)
add_subdirectory(voxedit)
add_subdirectory(profiler)
add_subdirectory(shapetool)
add_subdirectory(worldrenderertool)
add_subdirectory(noisetool)

View File

@ -0,0 +1,85 @@
find_package(Qt5Widgets)
if(Qt5Widgets_FOUND)
project(profiler)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
if(NOT DEFINED EASY_PROGRAM_VERSION_MAJOR)
set(EASY_PROGRAM_VERSION_MAJOR 1)
set(EASY_PROGRAM_VERSION_MINOR 0)
set(EASY_PROGRAM_VERSION_PATCH 0)
set(EASY_PRODUCT_VERSION_STRING "1.0.0")
endif(NOT DEFINED EASY_PROGRAM_VERSION_MAJOR)
add_definitions(
-DEASY_PROFILER_VERSION_MAJOR=${EASY_PROGRAM_VERSION_MAJOR}
-DEASY_PROFILER_VERSION_MINOR=${EASY_PROGRAM_VERSION_MINOR}
-DEASY_PROFILER_VERSION_PATCH=${EASY_PROGRAM_VERSION_PATCH}
)
set(SRCS
main.cpp
blocks_graphics_view.h
blocks_graphics_view.cpp
blocks_tree_widget.h
blocks_tree_widget.cpp
descriptors_tree_widget.h
descriptors_tree_widget.cpp
easy_chronometer_item.h
easy_chronometer_item.cpp
easy_graphics_item.h
easy_graphics_item.cpp
easy_graphics_scrollbar.h
easy_graphics_scrollbar.cpp
easy_qtimer.h
easy_qtimer.cpp
globals.h
globals.cpp
globals_qobjects.cpp
main_window.h
main_window.cpp
tree_widget_item.h
tree_widget_item.cpp
tree_widget_loader.h
tree_widget_loader.cpp
resources.qrc
resources.rc
)
engine_add_executable(TARGET ${PROJECT_NAME} SRCS ${SRCS} WINDOWED)
if (MINGW)
add_definitions(
-D_WIN32_WINNT=0x0600
-DSTRSAFE_NO_DEPRECATE
)
set (SPECIAL_LIB ${SPECIAL_LIB} ws2_32 psapi)
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
elseif (CMAKE_VERSION VERSION_LESS "3.1")
if (UNIX OR CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
set (CMAKE_CXX_FLAGS "-std=gnu++11 ${CMAKE_CXX_FLAGS}")
endif (UNIX OR CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
else ()
set_target_properties(${PROJECT_NAME} PROPERTIES
CXX_STANDARD 11
CXX_STANDARD_REQUIRED ON
)
endif (MINGW)
if(UNIX)
set(SPECIAL_LIB ${SPECIAL_LIB} pthread)
endif()
target_link_libraries(${PROJECT_NAME} easy_profiler ${SPECIAL_LIB})
target_include_directories(${PROJECT_NAME} PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
${AUTOGEN_TARGETS_FOLDER}
${AUTOMOC_TARGETS_FOLDER}
)
qt5_use_modules(${PROJECT_NAME} Widgets)
endif() # no QT

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,324 @@
/************************************************************************
* file name : blocks_graphics_view.h
* ----------------- :
* creation time : 2016/06/26
* author : Victor Zarubkin
* email : v.s.zarubkin@gmail.com
* ----------------- :
* description : The file contains declaration of GraphicsScene and GraphicsView and
* : it's auxiliary classes for displyaing easy_profiler blocks tree.
* ----------------- :
* change log : * 2016/06/26 Victor Zarubkin: moved sources from graphics_view.h
* : and renamed classes from My* to Prof*.
* :
* : * 2016/06/29 Victor Zarubkin: Highly optimized painting performance and memory consumption.
* :
* : * 2016/06/30 Victor Zarubkin: Replaced doubles with floats (in ProfBlockItem) for less memory consumption.
* :
* : * 2016/09/15 Victor Zarubkin: Moved sources of EasyGraphicsItem and EasyChronometerItem to separate files.
* :
* : *
* ----------------- :
* license : Lightweight profiler library for c++
* : Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
* :
* :
* : Licensed under the Apache License, Version 2.0 (the "License");
* : you may not use this file except in compliance with the License.
* : You may obtain a copy of the License at
* :
* : http://www.apache.org/licenses/LICENSE-2.0
* :
* : Unless required by applicable law or agreed to in writing, software
* : distributed under the License is distributed on an "AS IS" BASIS,
* : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* : See the License for the specific language governing permissions and
* : limitations under the License.
* :
* :
* : GNU General Public License Usage
* : Alternatively, this file may be used under the terms of the GNU
* : General Public License as published by the Free Software Foundation,
* : either version 3 of the License, or (at your option) any later version.
* :
* : This program is distributed in the hope that it will be useful,
* : but WITHOUT ANY WARRANTY; without even the implied warranty of
* : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
* : GNU General Public License for more details.
* :
* : You should have received a copy of the GNU General Public License
* : along with this program.If not, see <http://www.gnu.org/licenses/>.
************************************************************************/
#ifndef EASY__GRAPHICS_VIEW__H_
#define EASY__GRAPHICS_VIEW__H_
#include <stdlib.h>
#include <unordered_set>
#include <QGraphicsView>
#include <QGraphicsItem>
#include <QPoint>
#include <QRectF>
#include <QTimer>
#include <QLabel>
#include "easy/reader.h"
#include "common_types.h"
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
class QGraphicsProxyWidget;
class EasyGraphicsView;
class EasyGraphicsItem;
class EasyGraphicsScrollbar;
class EasyChronometerItem;
//////////////////////////////////////////////////////////////////////////
#define EASY_QGRAPHICSITEM(ClassName) \
class ClassName : public QGraphicsItem { \
QRectF m_boundingRect; \
public: \
ClassName() : QGraphicsItem() {} \
virtual ~ClassName() {} \
void paint(QPainter* _painter, const QStyleOptionGraphicsItem* _option, QWidget* _widget = nullptr) override; \
QRectF boundingRect() const override { return m_boundingRect; } \
void setBoundingRect(qreal x, qreal y, qreal w, qreal h) { m_boundingRect.setRect(x, y, w, h); } \
void setBoundingRect(const QRectF& _rect) { m_boundingRect = _rect; } \
}
EASY_QGRAPHICSITEM(EasyBackgroundItem);
EASY_QGRAPHICSITEM(EasyTimelineIndicatorItem);
EASY_QGRAPHICSITEM(EasyThreadNameItem);
#undef EASY_QGRAPHICSITEM
//////////////////////////////////////////////////////////////////////////
struct EasyBoldLabel : public QLabel {
EasyBoldLabel(const QString& _text, QWidget* _parent = nullptr);
virtual ~EasyBoldLabel();
};
//////////////////////////////////////////////////////////////////////////
class EasyGraphicsView : public QGraphicsView
{
Q_OBJECT
private:
typedef QGraphicsView Parent;
typedef EasyGraphicsView This;
typedef ::std::vector<EasyGraphicsItem*> Items;
typedef ::std::unordered_set<int, ::profiler_gui::do_no_hash<int>::hasher_t> Keys;
Items m_items; ///< Array of all EasyGraphicsItem items
Keys m_keys; ///< Pressed keys
::profiler_gui::TreeBlocks m_selectedBlocks; ///< Array of items which were selected by selection zone (EasyChronometerItem)
QTimer m_flickerTimer; ///< Timer for flicking behavior
QTimer m_idleTimer; ///<
QRectF m_visibleSceneRect; ///< Visible scene rectangle
::profiler::timestamp_t m_beginTime; ///< Begin time of profiler session. Used to reduce values of all begin and end times of profiler blocks.
qreal m_sceneWidth; ///<
qreal m_scale; ///< Current scale
qreal m_offset; ///< Have to use manual offset for all scene content instead of using scrollbars because QScrollBar::value is 32-bit integer :(
qreal m_timelineStep; ///<
uint64_t m_idleTime; ///<
QPoint m_mousePressPos; ///< Last mouse global position (used by mousePressEvent and mouseMoveEvent)
QPoint m_mouseMovePath; ///< Mouse move path between press and release of any button
Qt::MouseButtons m_mouseButtons; ///< Pressed mouse buttons
EasyGraphicsScrollbar* m_pScrollbar; ///< Pointer to the graphics scrollbar widget
EasyChronometerItem* m_chronometerItem; ///< Pointer to the EasyChronometerItem which is displayed when you press right mouse button and move mouse left or right. This item is used to select blocks to display in tree widget.
EasyChronometerItem* m_chronometerItemAux; ///< Pointer to the EasyChronometerItem which is displayed when you double click left mouse button and move mouse left or right. This item is used only to measure time.
QGraphicsProxyWidget* m_csInfoWidget; ///<
int m_flickerSpeedX; ///< Current flicking speed x
int m_flickerSpeedY; ///< Current flicking speed y
int m_flickerCounterX;
int m_flickerCounterY;
bool m_bDoubleClick; ///< Is mouse buttons double clicked
bool m_bUpdatingRect; ///< Stub flag which is used to avoid excess calculations on some scene update (flicking, scaling and so on)
bool m_bEmpty; ///< Indicates whether scene is empty and has no items
public:
explicit EasyGraphicsView(QWidget* _parent = nullptr);
virtual ~EasyGraphicsView();
// Public virtual methods
void wheelEvent(QWheelEvent* _event) override;
void mousePressEvent(QMouseEvent* _event) override;
void mouseDoubleClickEvent(QMouseEvent* _event) override;
void mouseReleaseEvent(QMouseEvent* _event) override;
void mouseMoveEvent(QMouseEvent* _event) override;
void keyPressEvent(QKeyEvent* _event) override;
void keyReleaseEvent(QKeyEvent* _event) override;
void resizeEvent(QResizeEvent* _event) override;
void dragEnterEvent(QDragEnterEvent*) override {}
public:
// Public non-virtual methods
qreal sceneWidth() const;
qreal chronoTime() const;
qreal chronoTimeAux() const;
void setScrollbar(EasyGraphicsScrollbar* _scrollbar);
void clear();
void setTree(const ::profiler::thread_blocks_tree_t& _blocksTree);
const Items& getItems() const;
signals:
// Signals
void sceneUpdated();
void treeChanged();
void intervalChanged(const ::profiler_gui::TreeBlocks& _blocks, ::profiler::timestamp_t _session_begin_time, ::profiler::timestamp_t _left, ::profiler::timestamp_t _right, bool _strict);
private:
// Private non-virtual methods
EasyChronometerItem* createChronometer(bool _main = true);
bool moveChrono(EasyChronometerItem* _chronometerItem, qreal _mouseX);
void initMode();
int updateVisibleSceneRect();
void updateTimelineStep(qreal _windowWidth);
void scaleTo(qreal _scale);
void scrollTo(const EasyGraphicsItem* _item);
void onWheel(qreal _mouseX, int _wheelDelta);
qreal setTree(EasyGraphicsItem* _item, const ::profiler::BlocksTree::children_t& _children, qreal& _height, uint32_t& _maxDepthChild, qreal _y, short _level);
private slots:
// Private Slots
void repaintScene();
void onGraphicsScrollbarWheel(qreal _mouseX, int _wheelDelta);
void onScrollbarValueChange(int);
void onGraphicsScrollbarValueChange(qreal);
void onFlickerTimeout();
void onIdleTimeout();
void onHierarchyFlagChange(bool _value);
void onSelectedThreadChange(::profiler::thread_id_t _id);
void onSelectedBlockChange(unsigned int _block_index);
void onRefreshRequired();
public:
// Public inline methods
inline qreal scale() const
{
return m_scale;
}
inline qreal offset() const
{
return m_offset;
}
inline const QRectF& visibleSceneRect() const
{
return m_visibleSceneRect;
}
inline qreal timelineStep() const
{
return m_timelineStep;
}
inline qreal time2position(const profiler::timestamp_t& _time) const
{
return PROF_MICROSECONDS(qreal(_time - m_beginTime));
//return PROF_MILLISECONDS(qreal(_time - m_beginTime));
}
inline ::profiler::timestamp_t position2time(qreal _pos) const
{
return PROF_FROM_MICROSECONDS(_pos);
//return PROF_FROM_MILLISECONDS(_pos);
}
}; // END of class EasyGraphicsView.
//////////////////////////////////////////////////////////////////////////
class EasyThreadNamesWidget : public QGraphicsView
{
Q_OBJECT
private:
typedef QGraphicsView Parent;
typedef EasyThreadNamesWidget This;
EasyGraphicsView* m_view;
const int m_additionalHeight;
public:
explicit EasyThreadNamesWidget(EasyGraphicsView* _view, int _additionalHeight, QWidget* _parent = nullptr);
virtual ~EasyThreadNamesWidget();
void mousePressEvent(QMouseEvent* _event) override;
void mouseDoubleClickEvent(QMouseEvent* _event) override;
void mouseReleaseEvent(QMouseEvent* _event) override;
void mouseMoveEvent(QMouseEvent* _event) override;
void keyPressEvent(QKeyEvent* _event) override;
void keyReleaseEvent(QKeyEvent* _event) override;
void wheelEvent(QWheelEvent* _event) override;
void dragEnterEvent(QDragEnterEvent*) override {}
void clear();
const EasyGraphicsView* view() const
{
return m_view;
}
private slots:
void setVerticalScrollbarRange(int _minValue, int _maxValue);
void onTreeChange();
void repaintScene();
}; // END of class EasyThreadNamesWidget.
//////////////////////////////////////////////////////////////////////////
class EasyGraphicsViewWidget : public QWidget
{
Q_OBJECT
private:
EasyGraphicsScrollbar* m_scrollbar;
EasyGraphicsView* m_view;
EasyThreadNamesWidget* m_threadNamesWidget;
public:
explicit EasyGraphicsViewWidget(QWidget* _parent = nullptr);
virtual ~EasyGraphicsViewWidget();
EasyGraphicsView* view();
void clear();
private:
void initWidget();
}; // END of class EasyGraphicsViewWidget.
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
#endif // EASY__GRAPHICS_VIEW__H_

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,204 @@
/************************************************************************
* file name : blocks_tree_widget.h
* ----------------- :
* creation time : 2016/06/26
* author : Victor Zarubkin
* email : v.s.zarubkin@gmail.com
* ----------------- :
* description : The file contains declaration of EasyTreeWidget and it's auxiliary classes
* : for displyaing EasyProfiler blocks tree.
* ----------------- :
* change log : * 2016/06/26 Victor Zarubkin: moved sources from tree_view.h
* : and renamed classes from My* to Prof*.
* :
* : * 2016/06/27 Victor Zarubkin: Added possibility to colorize rows
* : with profiler blocks' colors.
* :
* : * 2016/06/29 Victor Zarubkin: Added clearSilent() method.
* :
* : * 2016/08/18 Victor Zarubkin: Added loading blocks hierarchy in separate thread;
* : Moved sources of TreeWidgetItem into tree_widget_item.h/.cpp
* ----------------- :
* license : Lightweight profiler library for c++
* : Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
* :
* :
* : Licensed under the Apache License, Version 2.0 (the "License");
* : you may not use this file except in compliance with the License.
* : You may obtain a copy of the License at
* :
* : http://www.apache.org/licenses/LICENSE-2.0
* :
* : Unless required by applicable law or agreed to in writing, software
* : distributed under the License is distributed on an "AS IS" BASIS,
* : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* : See the License for the specific language governing permissions and
* : limitations under the License.
* :
* :
* : GNU General Public License Usage
* : Alternatively, this file may be used under the terms of the GNU
* : General Public License as published by the Free Software Foundation,
* : either version 3 of the License, or (at your option) any later version.
* :
* : This program is distributed in the hope that it will be useful,
* : but WITHOUT ANY WARRANTY; without even the implied warranty of
* : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
* : GNU General Public License for more details.
* :
* : You should have received a copy of the GNU General Public License
* : along with this program.If not, see <http://www.gnu.org/licenses/>.
************************************************************************/
#ifndef EASY__TREE_WIDGET__H_
#define EASY__TREE_WIDGET__H_
#include <QTreeWidget>
#include <QTimer>
#include "tree_widget_loader.h"
#include "tree_widget_item.h"
#include "easy/reader.h"
//////////////////////////////////////////////////////////////////////////
class EasyTreeWidget : public QTreeWidget
{
Q_OBJECT
typedef QTreeWidget Parent;
typedef EasyTreeWidget This;
protected:
EasyTreeWidgetLoader m_hierarchyBuilder;
Items m_items;
RootsMap m_roots;
::profiler_gui::TreeBlocks m_inputBlocks;
QTimer m_fillTimer;
QString m_lastSearch;
QTreeWidgetItem* m_lastFound;
::profiler::timestamp_t m_beginTime;
class QProgressDialog* m_progress;
EasyTreeMode m_mode;
bool m_bColorRows;
bool m_bLocked;
bool m_bSilentExpandCollapse;
char m_columnsHiddenStatus[COL_COLUMNS_NUMBER];
public:
explicit EasyTreeWidget(QWidget* _parent = nullptr);
virtual ~EasyTreeWidget();
void contextMenuEvent(QContextMenuEvent* _event) override;
void clearSilent(bool _global = false);
int findNext(const QString& _str, Qt::MatchFlags _flags);
int findPrev(const QString& _str, Qt::MatchFlags _flags);
public slots:
void setTree(const unsigned int _blocksNumber, const ::profiler::thread_blocks_tree_t& _blocksTree);
void setTreeBlocks(const ::profiler_gui::TreeBlocks& _blocks, ::profiler::timestamp_t _session_begin_time, ::profiler::timestamp_t _left, ::profiler::timestamp_t _right, bool _strict);
protected:
void resizeEvent(QResizeEvent* _event) override;
void moveEvent(QMoveEvent* _event) override;
private slots:
void onJumpToItemClicked(bool);
void onCollapseAllClicked(bool);
void onExpandAllClicked(bool);
void onCollapseAllChildrenClicked(bool);
void onExpandAllChildrenClicked(bool);
void onItemExpand(QTreeWidgetItem* _item);
void onItemCollapse(QTreeWidgetItem* _item);
void onCurrentItemChange(QTreeWidgetItem* _item, QTreeWidgetItem*);
void onColorizeRowsTriggered(bool _colorize);
void onSelectedThreadChange(::profiler::thread_id_t _id);
void onSelectedBlockChange(uint32_t _block_index);
void onBlockStatusChangeClicked(bool);
void resizeColumnsToContents();
void onHideShowColumn(bool);
void onModeChange(bool);
void onFillTimerTimeout();
protected:
void loadSettings();
void saveSettings();
void alignProgressBar();
}; // END of class EasyTreeWidget.
//////////////////////////////////////////////////////////////////////////
class EasyHierarchyWidget : public QWidget
{
Q_OBJECT
typedef QWidget Parent;
typedef EasyHierarchyWidget This;
private:
EasyTreeWidget* m_tree;
class QLineEdit* m_searchBox;
class QLabel* m_foundNumber;
class QAction* m_searchButton;
bool m_bCaseSensitiveSearch;
public:
// Public virtual methods
explicit EasyHierarchyWidget(QWidget* _parent = nullptr);
virtual ~EasyHierarchyWidget();
void keyPressEvent(QKeyEvent* _event) override;
void contextMenuEvent(QContextMenuEvent* _event) override;
public:
// Public non-virtual methods
EasyTreeWidget* tree();
void clear(bool _global = false);
private slots:
// Private slots
void onSeachBoxReturnPressed();
void findNext(bool);
void findPrev(bool);
void findNextFromMenu(bool);
void findPrevFromMenu(bool);
private:
// Private non-virtual methods
void loadSettings();
void saveSettings();
}; // END of class EasyHierarchyWidget.
//////////////////////////////////////////////////////////////////////////
#endif // EASY__TREE_WIDGET__H_

View File

@ -0,0 +1,470 @@
/************************************************************************
* file name : common_types.h
* ----------------- :
* creation time : 2016/07/31
* author : Victor Zarubkin
* email : v.s.zarubkin@gmail.com
* ----------------- :
* description : The file contains declaration of common types for both GraphicsView
* : and TreeWidget.
* ----------------- :
* change log : * 2016/07/31 Victor Zarubkin: initial commit.
* :
* : *
* ----------------- :
* license : Lightweight profiler library for c++
* : Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
* :
* : This program is free software : you can redistribute it and / or modify
* : it under the terms of the GNU General Public License as published by
* : the Free Software Foundation, either version 3 of the License, or
* : (at your option) any later version.
* :
* : This program is distributed in the hope that it will be useful,
* : but WITHOUT ANY WARRANTY; without even the implied warranty of
* : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
* : GNU General Public License for more details.
* :
* : You should have received a copy of the GNU General Public License
* : along with this program.If not, see <http://www.gnu.org/licenses/>.
************************************************************************/
#ifndef EASY_PROFILER__GUI_COMMON_TYPES_H
#define EASY_PROFILER__GUI_COMMON_TYPES_H
#include <stdlib.h>
#include <vector>
#include <unordered_map>
#include <QRgb>
#include <QString>
#include <QFont>
#include "easy/reader.h"
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
#define PROF_MICROSECONDS(timestamp) ((timestamp) * 1e-3)
//#define PROF_MICROSECONDS(timestamp) (timestamp)
#define PROF_FROM_MICROSECONDS(to_timestamp) ((to_timestamp) * 1e3)
//#define PROF_FROM_MICROSECONDS(to_timestamp) (to_timestamp)
#define PROF_MILLISECONDS(timestamp) ((timestamp) * 1e-6)
//#define PROF_MILLISECONDS(timestamp) ((timestamp) * 1e-3)
#define PROF_FROM_MILLISECONDS(to_timestamp) ((to_timestamp) * 1e6)
//#define PROF_FROM_MILLISECONDS(to_timestamp) ((to_timestamp) * 1e3)
#define PROF_NANOSECONDS(timestamp) (timestamp)
//#define PROF_NANOSECONDS(timestamp) ((timestamp) * 1000)
//////////////////////////////////////////////////////////////////////////
inline qreal units2microseconds(qreal _value)
{
return _value;
//return _value * 1e3;
}
inline qreal microseconds2units(qreal _value)
{
return _value;
//return _value * 1e-3;
}
//////////////////////////////////////////////////////////////////////////
namespace profiler_gui {
template <const size_t SIZEOF_T>
struct no_hasher {
template <class T> inline size_t operator () (const T& _data) const {
return (size_t)_data;
}
};
#ifdef _WIN64
template <> struct no_hasher<8> {
template <class T> inline size_t operator () (T _data) const {
return (size_t)_data;
}
};
#endif
template <> struct no_hasher<4> {
template <class T> inline size_t operator () (T _data) const {
return (size_t)_data;
}
};
template <> struct no_hasher<2> {
template <class T> inline size_t operator () (T _data) const {
return (size_t)_data;
}
};
template <> struct no_hasher<1> {
template <class T> inline size_t operator () (T _data) const {
return (size_t)_data;
}
};
template <class T>
struct do_no_hash {
typedef no_hasher<sizeof(T)> hasher_t;
};
//////////////////////////////////////////////////////////////////////////
inline QRgb toRgb(uint32_t _red, uint32_t _green, uint32_t _blue)
{
return (_red << 16) + (_green << 8) + _blue;
}
inline QRgb fromProfilerRgb(uint32_t _red, uint32_t _green, uint32_t _blue)
{
if (_red == 0 && _green == 0 && _blue == 0)
return ::profiler::colors::Default;
return toRgb(_red, _green, _blue) | 0x00141414;
}
inline bool isLightColor(::profiler::color_t _color)
{
const auto sum = 255. - (((_color & 0x00ff0000) >> 16) * 0.299 + ((_color & 0x0000ff00) >> 8) * 0.587 + (_color & 0x000000ff) * 0.114);
return sum < 76.5 || ((_color & 0xff000000) >> 24) < 0x80;
}
inline bool isLightColor(::profiler::color_t _color, qreal _maxSum)
{
const auto sum = 255. - (((_color & 0x00ff0000) >> 16) * 0.299 + ((_color & 0x0000ff00) >> 8) * 0.587 + (_color & 0x000000ff) * 0.114);
return sum < _maxSum || ((_color & 0xff000000) >> 24) < 0x80;
}
inline ::profiler::color_t textColorForFlag(bool _is_light)
{
return _is_light ? ::profiler::colors::Dark : ::profiler::colors::CreamWhite;
}
inline ::profiler::color_t textColorForRgb(::profiler::color_t _color)
{
return isLightColor(_color) ? ::profiler::colors::Dark : ::profiler::colors::CreamWhite;
}
//////////////////////////////////////////////////////////////////////////
#define EASY_GRAPHICS_ITEM_RECURSIVE_PAINT
//#undef EASY_GRAPHICS_ITEM_RECURSIVE_PAINT
#pragma pack(push, 1)
struct EasyBlockItem Q_DECL_FINAL
{
qreal x; ///< x coordinate of the item (this is made qreal=double to avoid mistakes on very wide scene)
float w; ///< Width of the item
::profiler::block_index_t block; ///< Index of profiler block
#ifndef EASY_GRAPHICS_ITEM_RECURSIVE_PAINT
::profiler::block_index_t neighbours; ///< Number of neighbours (parent.children.size())
uint32_t children_begin; ///< Index of first child item on the next sublevel
int8_t state; ///< 0 = no change, 1 = paint, -1 = do not paint
#else
::profiler::block_index_t max_depth_child; ///< Index of child with maximum tree depth
uint32_t children_begin; ///< Index of first child item on the next sublevel
#endif
// Possible optimizations:
// 1) We can save 1 more byte per block if we will use char instead of short + real time calculations for "totalHeight" var;
// 2) We can save 12 bytes per block if "x" and "w" vars will be removed (all this information exist inside BlocksTree),
// but this requires runtime x-coodinate calculation because BlocksTree has x value in nanoseconds.
inline void setPos(qreal _x, float _w) { x = _x; w = _w; }
inline qreal left() const { return x; }
inline qreal right() const { return x + w; }
inline float width() const { return w; }
}; // END of struct EasyBlockItem.
//#define EASY_TREE_WIDGET__USE_VECTOR
struct EasyBlock Q_DECL_FINAL
{
::profiler::BlocksTree tree;
#ifdef EASY_TREE_WIDGET__USE_VECTOR
uint32_t tree_item;
#endif
uint32_t graphics_item_index;
uint8_t graphics_item_level;
uint8_t graphics_item;
bool expanded;
EasyBlock() = default;
EasyBlock(EasyBlock&& that)
: tree(::std::move(that.tree))
#ifdef EASY_TREE_WIDGET__USE_VECTOR
, tree_item(that.tree_item)
#endif
, graphics_item_index(that.graphics_item_index)
, graphics_item_level(that.graphics_item_level)
, graphics_item(that.graphics_item)
, expanded(that.expanded)
{
}
private:
EasyBlock(const EasyBlock&) = delete;
};
#pragma pack(pop)
typedef ::std::vector<EasyBlockItem> EasyItems;
typedef ::std::vector<EasyBlock> EasyBlocks;
//////////////////////////////////////////////////////////////////////////
struct EasySelectedBlock Q_DECL_FINAL
{
const ::profiler::BlocksTreeRoot* root;
::profiler::block_index_t tree;
EasySelectedBlock() : root(nullptr), tree(0xffffffff)
{
}
EasySelectedBlock(const ::profiler::BlocksTreeRoot* _root, const ::profiler::block_index_t _tree)
: root(_root)
, tree(_tree)
{
}
}; // END of struct EasySelectedBlock.
typedef ::std::vector<EasySelectedBlock> TreeBlocks;
//////////////////////////////////////////////////////////////////////////
enum TimeUnits : int8_t
{
TimeUnits_ms = 0,
TimeUnits_us,
TimeUnits_ns,
TimeUnits_auto
}; // END of enum TimeUnits.
inline qreal timeFactor(qreal _interval)
{
if (_interval < 1) // interval in nanoseconds
return 1e3;
if (_interval < 1e3) // interval in microseconds
return 1;
if (_interval < 1e6) // interval in milliseconds
return 1e-3;
// interval in seconds
return 1e-6;
}
inline QString autoTimeStringReal(qreal _interval, int _precision = 1)
{
if (_interval < 1) // interval in nanoseconds
return QString("%1 ns").arg(static_cast<quint64>(_interval * 1e3));
if (_interval < 1e3) // interval in microseconds
return QString("%1 us").arg(_interval, 0, 'f', _precision);
if (_interval < 1e6) // interval in milliseconds
return QString("%1 ms").arg(_interval * 1e-3, 0, 'f', _precision);
// interval in seconds
return QString("%1 s").arg(_interval * 1e-6, 0, 'f', _precision);
}
inline QString autoTimeStringInt(qreal _interval)
{
if (_interval < 1) // interval in nanoseconds
return QString("%1 ns").arg(static_cast<quint64>(_interval * 1e3));
if (_interval < 1e3) // interval in microseconds
return QString("%1 us").arg(static_cast<quint32>(_interval));
if (_interval < 1e6) // interval in milliseconds
return QString("%1 ms").arg(static_cast<quint32>(_interval * 1e-3));
// interval in seconds
return QString("%1 s").arg(static_cast<quint32>(_interval * 1e-6));
}
inline QString autoTimeStringRealNs(::profiler::timestamp_t _interval, int _precision = 1)
{
if (_interval < 1000) // interval in nanoseconds
return QString("%1 ns").arg(_interval);
if (_interval < 1000000) // interval in microseconds
return QString("%1 us").arg(_interval * 1e-3, 0, 'f', _precision);
if (_interval < 1000000000U) // interval in milliseconds
return QString("%1 ms").arg(_interval * 1e-6, 0, 'f', _precision);
// interval in seconds
return QString("%1 s").arg(_interval * 1e-9, 0, 'f', _precision);
}
inline QString autoTimeStringIntNs(::profiler::timestamp_t _interval)
{
if (_interval < 1000) // interval in nanoseconds
return QString("%1 ns").arg(_interval);
if (_interval < 1000000) // interval in microseconds
return QString("%1 us").arg(static_cast<quint32>(_interval * 1e-3));
if (_interval < 1000000000U) // interval in milliseconds
return QString("%1 ms").arg(static_cast<quint32>(_interval * 1e-6));
// interval in seconds
return QString("%1 s").arg(static_cast<quint32>(_interval * 1e-9));
}
inline QString timeStringReal(TimeUnits _units, qreal _interval, int _precision = 1)
{
switch (_units)
{
case TimeUnits_ms:{
const char fmt = _interval <= 1 ? 'g' : 'f';
return QString("%1 ms").arg(_interval * 1e-3, 0, fmt, _precision);
}
case TimeUnits_us:
return QString("%1 us").arg(_interval, 0, 'f', _precision);
case TimeUnits_ns:
return QString("%1 ns").arg(static_cast<quint64>(_interval * 1e3));
case TimeUnits_auto:
default:
return autoTimeStringReal(_interval, _precision);
}
return QString();
}
inline QString timeStringRealNs(TimeUnits _units, ::profiler::timestamp_t _interval, int _precision = 1)
{
switch (_units)
{
case TimeUnits_ms:{
const char fmt = _interval <= 1000 ? 'g' : 'f';
return QString("%1 ms").arg(_interval * 1e-6, 0, fmt, _precision);
}
case TimeUnits_us:
return QString("%1 us").arg(_interval * 1e-3, 0, 'f', _precision);
case TimeUnits_ns:
return QString("%1 ns").arg(_interval);
case TimeUnits_auto:
default:
return autoTimeStringRealNs(_interval, _precision);
}
return QString();
}
inline QString timeStringInt(TimeUnits _units, qreal _interval)
{
switch (_units)
{
case TimeUnits_ms:
return QString("%1 ms").arg(static_cast<quint32>(_interval * 1e-3));
case TimeUnits_us:
return QString("%1 us").arg(static_cast<quint32>(_interval));
case TimeUnits_ns:
return QString("%1 ns").arg(static_cast<quint64>(_interval * 1e3));
case TimeUnits_auto:
default:
return autoTimeStringInt(_interval);
}
return QString();
}
inline QString timeStringIntNs(TimeUnits _units, ::profiler::timestamp_t _interval)
{
switch (_units)
{
case TimeUnits_ms:
return QString("%1 ms").arg(static_cast<quint32>(_interval * 1e-6));
case TimeUnits_us:
return QString("%1 us").arg(static_cast<quint32>(_interval * 1e-3));
case TimeUnits_ns:
return QString("%1 ns").arg(_interval);
case TimeUnits_auto:
default:
return autoTimeStringIntNs(_interval);
}
return QString();
}
//////////////////////////////////////////////////////////////////////////
template <class T> inline T numeric_max() {
return ::std::numeric_limits<T>::max();
}
template <class T> inline T numeric_max(T) {
return ::std::numeric_limits<T>::max();
}
template <class T> inline void set_max(T& _value) {
_value = ::std::numeric_limits<T>::max();
}
template <class T> inline bool is_max(const T& _value) {
return _value == ::std::numeric_limits<T>::max();
}
//////////////////////////////////////////////////////////////////////////
inline double percentReal(::profiler::timestamp_t _partial, ::profiler::timestamp_t _total)
{
return _total ? 100. * static_cast<double>(_partial) / static_cast<double>(_total) : 0.;
}
inline int percent(::profiler::timestamp_t _partial, ::profiler::timestamp_t _total)
{
return static_cast<int>(0.5 + percentReal(_partial, _total));
}
//////////////////////////////////////////////////////////////////////////
inline QFont EFont(QFont::StyleHint _hint, const char* _family, int _size, int _weight = -1)
{
QFont f;
f.setStyleHint(_hint, QFont::PreferMatch);
f.setFamily(_family);
f.setPointSize(_size);
f.setWeight(_weight);
return f;
}
inline QFont EFont(const char* _family, int _size, int _weight = -1)
{
return EFont(QFont::Helvetica, _family, _size, _weight);
}
//////////////////////////////////////////////////////////////////////////
} // END of namespace profiler_gui.
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
#endif // EASY_PROFILER__GUI_COMMON_TYPES_H

View File

@ -0,0 +1,905 @@
/************************************************************************
* file name : descriptors_tree_widget.cpp
* ----------------- :
* creation time : 2016/09/17
* author : Victor Zarubkin
* email : v.s.zarubkin@gmail.com
* ----------------- :
* description : The file contains implementation of EasyDescTreeWidget and it's auxiliary classes
* : for displyaing EasyProfiler blocks descriptors tree.
* ----------------- :
* change log : * 2016/09/17 Victor Zarubkin: initial commit.
* :
* : *
* ----------------- :
* license : Lightweight profiler library for c++
* : Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
* :
* :
* : Licensed under the Apache License, Version 2.0 (the "License");
* : you may not use this file except in compliance with the License.
* : You may obtain a copy of the License at
* :
* : http://www.apache.org/licenses/LICENSE-2.0
* :
* : Unless required by applicable law or agreed to in writing, software
* : distributed under the License is distributed on an "AS IS" BASIS,
* : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* : See the License for the specific language governing permissions and
* : limitations under the License.
* :
* :
* : GNU General Public License Usage
* : Alternatively, this file may be used under the terms of the GNU
* : General Public License as published by the Free Software Foundation,
* : either version 3 of the License, or (at your option) any later version.
* :
* : This program is distributed in the hope that it will be useful,
* : but WITHOUT ANY WARRANTY; without even the implied warranty of
* : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
* : GNU General Public License for more details.
* :
* : You should have received a copy of the GNU General Public License
* : along with this program.If not, see <http://www.gnu.org/licenses/>.
************************************************************************/
#include <QMenu>
#include <QAction>
#include <QActionGroup>
#include <QHeaderView>
#include <QString>
#include <QContextMenuEvent>
#include <QKeyEvent>
#include <QSignalBlocker>
#include <QSettings>
#include <QLabel>
#include <QLineEdit>
#include <QToolBar>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QTimer>
#include <thread>
#include "descriptors_tree_widget.h"
#include "globals.h"
#ifdef _WIN32
#include <Windows.h>
#include <processthreadsapi.h>
#endif
#ifdef max
#undef max
#endif
#ifdef min
#undef min
#endif
//////////////////////////////////////////////////////////////////////////
enum DescColumns
{
DESC_COL_FILE_LINE = 0,
DESC_COL_TYPE,
DESC_COL_NAME,
DESC_COL_STATUS,
DESC_COL_COLUMNS_NUMBER
};
//////////////////////////////////////////////////////////////////////////
::profiler::EasyBlockStatus nextStatus(::profiler::EasyBlockStatus _status)
{
switch (_status)
{
case ::profiler::OFF:
return ::profiler::ON;
case ::profiler::ON:
return ::profiler::FORCE_ON;
case ::profiler::FORCE_ON:
return ::profiler::OFF_RECURSIVE;
case ::profiler::OFF_RECURSIVE:
return ::profiler::ON_WITHOUT_CHILDREN;
case ::profiler::ON_WITHOUT_CHILDREN:
return ::profiler::FORCE_ON_WITHOUT_CHILDREN;
case ::profiler::FORCE_ON_WITHOUT_CHILDREN:
return ::profiler::OFF;
}
return ::profiler::OFF;
}
const char* statusText(::profiler::EasyBlockStatus _status)
{
switch (_status)
{
case ::profiler::OFF:
return "OFF";
case ::profiler::ON:
return "ON";
case ::profiler::FORCE_ON:
return "FORCE_ON";
case ::profiler::OFF_RECURSIVE:
return "OFF_RECURSIVE";
case ::profiler::ON_WITHOUT_CHILDREN:
return "ON_WITHOUT_CHILDREN";
case ::profiler::FORCE_ON_WITHOUT_CHILDREN:
return "FORCE_ON_WITHOUT_CHILDREN";
}
return "";
}
::profiler::color_t statusColor(::profiler::EasyBlockStatus _status)
{
switch (_status)
{
case ::profiler::OFF:
return ::profiler::colors::Red900;
case ::profiler::ON:
return ::profiler::colors::LightGreen900;
case ::profiler::FORCE_ON:
return ::profiler::colors::LightGreen900;
case ::profiler::OFF_RECURSIVE:
return ::profiler::colors::Red900;
case ::profiler::ON_WITHOUT_CHILDREN:
return ::profiler::colors::Lime900;
case ::profiler::FORCE_ON_WITHOUT_CHILDREN:
return ::profiler::colors::Lime900;
}
return ::profiler::colors::Black;
}
//////////////////////////////////////////////////////////////////////////
EasyDescWidgetItem::EasyDescWidgetItem(::profiler::block_id_t _desc, Parent* _parent) : Parent(_parent), m_desc(_desc)
{
}
EasyDescWidgetItem::~EasyDescWidgetItem()
{
}
bool EasyDescWidgetItem::operator < (const Parent& _other) const
{
const auto col = treeWidget()->sortColumn();
switch (col)
{
case DESC_COL_FILE_LINE:
{
if (parent() != nullptr)
return data(col, Qt::UserRole).toInt() < _other.data(col, Qt::UserRole).toInt();
}
}
return Parent::operator < (_other);
}
//////////////////////////////////////////////////////////////////////////
EasyDescTreeWidget::EasyDescTreeWidget(QWidget* _parent)
: Parent(_parent)
, m_lastFound(nullptr)
, m_lastSearchColumn(-1)
, m_searchColumn(DESC_COL_NAME)
, m_bLocked(false)
{
setAutoFillBackground(false);
setAlternatingRowColors(true);
setItemsExpandable(true);
setAnimated(true);
setSortingEnabled(false);
setColumnCount(DESC_COL_COLUMNS_NUMBER);
auto header_item = new QTreeWidgetItem();
header_item->setText(DESC_COL_FILE_LINE, "File/Line");
header_item->setText(DESC_COL_TYPE, "Type");
header_item->setText(DESC_COL_NAME, "Name");
header_item->setText(DESC_COL_STATUS, "Status");
setHeaderItem(header_item);
connect(&EASY_GLOBALS.events, &::profiler_gui::EasyGlobalSignals::selectedBlockChanged, this, &This::onSelectedBlockChange);
connect(&EASY_GLOBALS.events, &::profiler_gui::EasyGlobalSignals::blockStatusChanged, this, &This::onBlockStatusChange);
connect(this, &Parent::itemExpanded, this, &This::onItemExpand);
connect(this, &Parent::itemDoubleClicked, this, &This::onDoubleClick);
connect(this, &Parent::currentItemChanged, this, &This::onCurrentItemChange);
loadSettings();
}
EasyDescTreeWidget::~EasyDescTreeWidget()
{
if (::profiler_gui::is_max(EASY_GLOBALS.selected_block) && !::profiler_gui::is_max(EASY_GLOBALS.selected_block_id))
{
::profiler_gui::set_max(EASY_GLOBALS.selected_block_id);
emit EASY_GLOBALS.events.refreshRequired();
}
saveSettings();
}
//////////////////////////////////////////////////////////////////////////
void EasyDescTreeWidget::contextMenuEvent(QContextMenuEvent* _event)
{
_event->accept();
QMenu menu;
menu.setToolTipsVisible(true);
auto action = menu.addAction("Expand all");
SET_ICON(action, ":/Expand");
connect(action, &QAction::triggered, this, &This::expandAll);
action = menu.addAction("Collapse all");
SET_ICON(action, ":/Collapse");
connect(action, &QAction::triggered, this, &This::collapseAll);
menu.addSeparator();
auto submenu = menu.addMenu("Search by");
auto header_item = headerItem();
for (int i = 0; i < DESC_COL_STATUS; ++i)
{
if (i == DESC_COL_TYPE)
continue;
action = submenu->addAction(header_item->text(i));
action->setData(i);
action->setCheckable(true);
if (i == m_searchColumn)
action->setChecked(true);
connect(action, &QAction::triggered, this, &This::onSearchColumnChange);
}
auto item = currentItem();
if (item != nullptr && item->parent() != nullptr && currentColumn() >= DESC_COL_TYPE)
{
const auto& desc = easyDescriptor(static_cast<EasyDescWidgetItem*>(item)->desc());
menu.addSeparator();
auto submenu = menu.addMenu("Change status");
submenu->setToolTipsVisible(true);
#define ADD_STATUS_ACTION(NameValue, StatusValue, ToolTipValue)\
action = submenu->addAction(NameValue);\
action->setCheckable(true);\
action->setChecked(desc.status() == StatusValue);\
action->setData(static_cast<quint32>(StatusValue));\
action->setToolTip(ToolTipValue);\
connect(action, &QAction::triggered, this, &This::onBlockStatusChangeClicked)
ADD_STATUS_ACTION("Off", ::profiler::OFF, "Do not profile this block.");
ADD_STATUS_ACTION("On", ::profiler::ON, "Profile this block\nif parent enabled children.");
ADD_STATUS_ACTION("Force-On", ::profiler::FORCE_ON, "Always profile this block even\nif it's parent disabled children.");
ADD_STATUS_ACTION("Off-recursive", ::profiler::OFF_RECURSIVE, "Do not profile neither this block\nnor it's children.");
ADD_STATUS_ACTION("On-without-children", ::profiler::ON_WITHOUT_CHILDREN, "Profile this block, but\ndo not profile it's children.");
ADD_STATUS_ACTION("Force-On-without-children", ::profiler::FORCE_ON_WITHOUT_CHILDREN, "Always profile this block, but\ndo not profile it's children.");
#undef ADD_STATUS_ACTION
submenu->setEnabled(EASY_GLOBALS.connected);
if (!EASY_GLOBALS.connected)
submenu->setTitle(QString("%1 (connection needed)").arg(submenu->title()));
}
menu.exec(QCursor::pos());
}
void EasyDescTreeWidget::onSearchColumnChange(bool)
{
auto action = qobject_cast<QAction*>(sender());
if (action != nullptr)
m_searchColumn = action->data().toInt();
}
//////////////////////////////////////////////////////////////////////////
void EasyDescTreeWidget::clearSilent(bool _global)
{
const QSignalBlocker b(this);
setSortingEnabled(false);
m_lastFound = nullptr;
m_lastSearch.clear();
m_highlightItems.clear();
m_items.clear();
::std::vector<QTreeWidgetItem*> topLevelItems;
topLevelItems.reserve(topLevelItemCount());
for (int i = topLevelItemCount() - 1; i >= 0; --i)
{
const bool expanded = !_global && topLevelItem(i)->isExpanded();
auto item = takeTopLevelItem(i);
if (expanded)
m_expandedFilesTemp.insert(item->text(DESC_COL_FILE_LINE).toStdString());
topLevelItems.push_back(item);
}
auto deleter_thread = ::std::thread([](decltype(topLevelItems) _items)
{
#ifdef _WIN32
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_LOWEST);
#endif
for (auto item : _items)
delete item;
}, ::std::move(topLevelItems));
deleter_thread.detach();
//clear();
}
//////////////////////////////////////////////////////////////////////////
struct FileItems
{
typedef ::std::unordered_map<int, EasyDescWidgetItem*, ::profiler_gui::do_no_hash<int>::hasher_t> Items;
Items children;
QTreeWidgetItem* item = nullptr;
};
void EasyDescTreeWidget::build()
{
auto f = font();
f.setBold(true);
typedef ::std::unordered_map<::std::string, FileItems> Files;
Files fileItems;
m_items.resize(EASY_GLOBALS.descriptors.size());
memset(m_items.data(), 0, sizeof(void*) * m_items.size());
const QSignalBlocker b(this);
::profiler::block_id_t id = 0;
for (auto desc : EASY_GLOBALS.descriptors)
{
if (desc != nullptr)
{
auto& p = fileItems[desc->file()];
if (p.item == nullptr)
{
p.item = new QTreeWidgetItem();
p.item->setText(DESC_COL_FILE_LINE, desc->file());
p.item->setText(DESC_COL_TYPE, "F");
p.item->setToolTip(DESC_COL_TYPE, "File");
}
auto it = p.children.find(desc->line());
if (it == p.children.end())
{
auto item = new EasyDescWidgetItem(desc->id(), p.item);
item->setText(DESC_COL_FILE_LINE, QString::number(desc->line()));
item->setData(DESC_COL_FILE_LINE, Qt::UserRole, desc->line());
item->setText(DESC_COL_NAME, desc->name());
if (desc->type() == ::profiler::BLOCK_TYPE_BLOCK)
{
item->setText(DESC_COL_TYPE, "B");
item->setToolTip(DESC_COL_TYPE, "Block");
}
else
{
item->setText(DESC_COL_TYPE, "E");
item->setToolTip(DESC_COL_TYPE, "Event");
}
item->setFont(DESC_COL_STATUS, f);
item->setText(DESC_COL_STATUS, statusText(desc->status()));
item->setForeground(DESC_COL_STATUS, QColor::fromRgba(statusColor(desc->status())));
m_items[id] = item;
p.children.insert(::std::make_pair(desc->line(), item));
}
else
{
m_items[id] = it->second;
}
}
++id;
}
for (auto& p : fileItems)
{
addTopLevelItem(p.second.item);
if (m_expandedFilesTemp.find(p.first) != m_expandedFilesTemp.end())
p.second.item->setExpanded(true);
}
m_expandedFilesTemp.clear();
setSortingEnabled(true);
sortByColumn(DESC_COL_FILE_LINE, Qt::AscendingOrder);
resizeColumnsToContents();
QTimer::singleShot(100, [this](){ onSelectedBlockChange(EASY_GLOBALS.selected_block); });
}
//////////////////////////////////////////////////////////////////////////
void EasyDescTreeWidget::onItemExpand(QTreeWidgetItem*)
{
resizeColumnsToContents();
}
//////////////////////////////////////////////////////////////////////////
void EasyDescTreeWidget::onDoubleClick(QTreeWidgetItem* _item, int _column)
{
if (!EASY_GLOBALS.connected)
return;
if (_column >= DESC_COL_TYPE && _item->parent() != nullptr)
{
auto item = static_cast<EasyDescWidgetItem*>(_item);
auto& desc = easyDescriptor(item->desc());
desc.setStatus(nextStatus(desc.status()));
item->setText(DESC_COL_STATUS, statusText(desc.status()));
item->setForeground(DESC_COL_STATUS, QColor::fromRgba(statusColor(desc.status())));
m_bLocked = true;
emit EASY_GLOBALS.events.blockStatusChanged(desc.id(), desc.status());
m_bLocked = false;
}
}
//////////////////////////////////////////////////////////////////////////
void EasyDescTreeWidget::onCurrentItemChange(QTreeWidgetItem* _item, QTreeWidgetItem* _prev)
{
if (_prev != nullptr)
{
auto f = font();
for (int i = 0; i < DESC_COL_STATUS; ++i)
_prev->setFont(i, f);
}
if (_item != nullptr)
{
auto f = font();
f.setBold(true);
for (int i = 0; i < DESC_COL_STATUS; ++i)
_item->setFont(i, f);
if (::profiler_gui::is_max(EASY_GLOBALS.selected_block) && _item->parent() != nullptr)
{
const auto id = static_cast<EasyDescWidgetItem*>(_item)->desc();
if (EASY_GLOBALS.selected_block_id != id)
{
EASY_GLOBALS.selected_block_id = id;
emit EASY_GLOBALS.events.selectedBlockIdChanged(id);
}
}
}
else if (::profiler_gui::is_max(EASY_GLOBALS.selected_block) && !::profiler_gui::is_max(EASY_GLOBALS.selected_block_id))
{
::profiler_gui::set_max(EASY_GLOBALS.selected_block_id);
emit EASY_GLOBALS.events.selectedBlockIdChanged(EASY_GLOBALS.selected_block_id);
}
}
//////////////////////////////////////////////////////////////////////////
void EasyDescTreeWidget::onBlockStatusChangeClicked(bool _checked)
{
if (!_checked || !EASY_GLOBALS.connected)
return;
auto item = currentItem();
if (item == nullptr || item->parent() == nullptr)
return;
auto action = qobject_cast<QAction*>(sender());
if (action != nullptr)
{
auto& desc = easyDescriptor(static_cast<EasyDescWidgetItem*>(item)->desc());
desc.setStatus(static_cast<::profiler::EasyBlockStatus>(action->data().toUInt()));
item->setText(DESC_COL_STATUS, statusText(desc.status()));
item->setForeground(DESC_COL_STATUS, QColor::fromRgba(statusColor(desc.status())));
m_bLocked = true;
emit EASY_GLOBALS.events.blockStatusChanged(desc.id(), desc.status());
m_bLocked = false;
}
}
void EasyDescTreeWidget::onBlockStatusChange(::profiler::block_id_t _id, ::profiler::EasyBlockStatus _status)
{
if (m_bLocked)
return;
auto item = m_items[_id];
if (item == nullptr)
return;
auto& desc = easyDescriptor(item->desc());
item->setText(DESC_COL_STATUS, statusText(desc.status()));
item->setForeground(DESC_COL_STATUS, QColor::fromRgba(statusColor(desc.status())));
}
//////////////////////////////////////////////////////////////////////////
void EasyDescTreeWidget::resizeColumnsToContents()
{
for (int i = 0; i < DESC_COL_COLUMNS_NUMBER; ++i)
resizeColumnToContents(i);
}
//////////////////////////////////////////////////////////////////////////
void EasyDescTreeWidget::onSelectedBlockChange(uint32_t _block_index)
{
if (::profiler_gui::is_max(_block_index))
return;
auto item = m_items[blocksTree(_block_index).node->id()];
if (item == nullptr)
return;
scrollToItem(item, QAbstractItemView::PositionAtCenter);
setCurrentItem(item);
}
//////////////////////////////////////////////////////////////////////////
void EasyDescTreeWidget::resetHighlight()
{
for (auto item : m_highlightItems) {
for (int i = 0; i < DESC_COL_COLUMNS_NUMBER; ++i)
item->setBackground(i, Qt::NoBrush);
}
m_highlightItems.clear();
}
void EasyDescTreeWidget::loadSettings()
{
QSettings settings(::profiler_gui::ORGANAZATION_NAME, ::profiler_gui::APPLICATION_NAME);
settings.beginGroup("desc_tree_widget");
auto val = settings.value("searchColumn");
if (!val.isNull())
m_searchColumn = val.toInt();
settings.endGroup();
}
void EasyDescTreeWidget::saveSettings()
{
QSettings settings(::profiler_gui::ORGANAZATION_NAME, ::profiler_gui::APPLICATION_NAME);
settings.beginGroup("desc_tree_widget");
settings.setValue("searchColumn", m_searchColumn);
settings.endGroup();
}
//////////////////////////////////////////////////////////////////////////
int EasyDescTreeWidget::findNext(const QString& _str, Qt::MatchFlags _flags)
{
if (_str.isEmpty())
{
resetHighlight();
m_lastSearchColumn = m_searchColumn;
return 0;
}
const bool isNewSearch = (m_lastSearchColumn != m_searchColumn || m_lastSearch != _str);
auto itemsList = findItems(_str, Qt::MatchContains | Qt::MatchRecursive | _flags, m_searchColumn);
if (!isNewSearch)
{
if (!itemsList.empty())
{
bool stop = false;
decltype(m_lastFound) next = nullptr;
for (auto item : itemsList)
{
if (stop)
{
next = item;
break;
}
stop = item == m_lastFound;
}
m_lastFound = next == nullptr ? itemsList.front() : next;
}
else
{
m_lastFound = nullptr;
}
}
else
{
resetHighlight();
m_lastSearchColumn = m_searchColumn;
m_lastSearch = _str;
m_lastFound = !itemsList.empty() ? itemsList.front() : nullptr;
for (auto item : itemsList)
{
m_highlightItems.push_back(item);
for (int i = 0; i < DESC_COL_COLUMNS_NUMBER; ++i)
item->setBackgroundColor(i, QColor::fromRgba(0x80000000 | (0x00ffffff & ::profiler::colors::Yellow)));
}
}
if (m_lastFound != nullptr)
{
scrollToItem(m_lastFound, QAbstractItemView::PositionAtCenter);
setCurrentItem(m_lastFound);
}
return itemsList.size();
}
int EasyDescTreeWidget::findPrev(const QString& _str, Qt::MatchFlags _flags)
{
if (_str.isEmpty())
{
resetHighlight();
m_lastSearchColumn = m_searchColumn;
return 0;
}
const bool isNewSearch = (m_lastSearchColumn != m_searchColumn || m_lastSearch != _str);
auto itemsList = findItems(_str, Qt::MatchContains | Qt::MatchRecursive | _flags, m_searchColumn);
if (!isNewSearch)
{
if (!itemsList.empty())
{
decltype(m_lastFound) prev = nullptr;
for (auto item : itemsList)
{
if (item == m_lastFound)
break;
prev = item;
}
m_lastFound = prev == nullptr ? itemsList.back() : prev;
}
else
{
m_lastFound = nullptr;
}
}
else
{
resetHighlight();
m_lastSearchColumn = m_searchColumn;
m_lastSearch = _str;
m_lastFound = !itemsList.empty() ? itemsList.front() : nullptr;
m_highlightItems.reserve(itemsList.size());
for (auto item : itemsList)
{
m_highlightItems.push_back(item);
for (int i = 0; i < DESC_COL_COLUMNS_NUMBER; ++i)
item->setBackgroundColor(i, QColor::fromRgba(0x80000000 | (0x00ffffff & ::profiler::colors::Yellow)));
}
}
if (m_lastFound != nullptr)
{
scrollToItem(m_lastFound, QAbstractItemView::PositionAtCenter);
setCurrentItem(m_lastFound);
}
return itemsList.size();
}
//////////////////////////////////////////////////////////////////////////
EasyDescWidget::EasyDescWidget(QWidget* _parent) : Parent(_parent)
, m_tree(new EasyDescTreeWidget(this))
, m_searchBox(new QLineEdit(this))
, m_foundNumber(new QLabel("Found 0 matches", this))
, m_searchButton(nullptr)
, m_bCaseSensitiveSearch(false)
{
loadSettings();
m_searchBox->setFixedWidth(200);
m_searchBox->setContentsMargins(5, 0, 0, 0);
auto tb = new QToolBar(this);
tb->setIconSize(::profiler_gui::ICONS_SIZE);
auto refreshButton = tb->addAction(QIcon(":/Reload"), tr("Refresh blocks list"));
refreshButton->setEnabled(EASY_GLOBALS.connected);
refreshButton->setToolTip(tr("Refresh blocks list.\nConnection needed."));
connect(refreshButton, &QAction::triggered, &EASY_GLOBALS.events, &::profiler_gui::EasyGlobalSignals::blocksRefreshRequired);
QMenu* menu = new QMenu(this);
m_searchButton = menu->menuAction();
m_searchButton->setText("Find next");
m_searchButton->setIcon(QIcon(":/Search-next"));
m_searchButton->setData(true);
connect(m_searchButton, &QAction::triggered, this, &This::findNext);
auto actionGroup = new QActionGroup(this);
actionGroup->setExclusive(true);
auto a = new QAction(tr("Find next"), actionGroup);
a->setCheckable(true);
a->setChecked(true);
connect(a, &QAction::triggered, this, &This::findNextFromMenu);
menu->addAction(a);
a = new QAction(tr("Find previous"), actionGroup);
a->setCheckable(true);
connect(a, &QAction::triggered, this, &This::findPrevFromMenu);
menu->addAction(a);
menu->addSeparator();
a = menu->addAction("Case sensitive");
a->setCheckable(true);
a->setChecked(m_bCaseSensitiveSearch);
connect(a, &QAction::triggered, [this](bool _checked){ m_bCaseSensitiveSearch = _checked; });
menu->addAction(a);
tb->addSeparator();
tb->addAction(m_searchButton);
tb->addWidget(m_searchBox);
auto searchbox = new QHBoxLayout();
searchbox->setContentsMargins(0, 0, 5, 0);
searchbox->addWidget(tb);
searchbox->addStretch(100);
searchbox->addWidget(m_foundNumber, Qt::AlignRight);
auto lay = new QVBoxLayout(this);
lay->setContentsMargins(1, 1, 1, 1);
lay->addLayout(searchbox);
lay->addWidget(m_tree);
connect(m_searchBox, &QLineEdit::returnPressed, this, &This::onSeachBoxReturnPressed);
connect(&EASY_GLOBALS.events, &::profiler_gui::EasyGlobalSignals::connectionChanged, refreshButton, &QAction::setEnabled);
}
EasyDescWidget::~EasyDescWidget()
{
saveSettings();
}
void EasyDescWidget::loadSettings()
{
QSettings settings(::profiler_gui::ORGANAZATION_NAME, ::profiler_gui::APPLICATION_NAME);
settings.beginGroup("EasyDescWidget");
auto val = settings.value("case_sensitive");
if (!val.isNull())
m_bCaseSensitiveSearch = val.toBool();
settings.endGroup();
}
void EasyDescWidget::saveSettings()
{
QSettings settings(::profiler_gui::ORGANAZATION_NAME, ::profiler_gui::APPLICATION_NAME);
settings.beginGroup("EasyDescWidget");
settings.setValue("case_sensitive", m_bCaseSensitiveSearch);
settings.endGroup();
}
void EasyDescWidget::keyPressEvent(QKeyEvent* _event)
{
if (_event->key() == Qt::Key_F3)
{
if (_event->modifiers() & Qt::ShiftModifier)
findPrev(true);
else
findNext(true);
}
_event->accept();
}
void EasyDescWidget::contextMenuEvent(QContextMenuEvent* _event)
{
m_tree->contextMenuEvent(_event);
}
void EasyDescWidget::build()
{
m_tree->clearSilent(false);
m_foundNumber->setText(QString("Found 0 matches"));
m_tree->build();
}
void EasyDescWidget::clear()
{
m_tree->clearSilent(true);
m_foundNumber->setText(QString("Found 0 matches"));
}
void EasyDescWidget::onSeachBoxReturnPressed()
{
if (m_searchButton->data().toBool() == true)
findNext(true);
else
findPrev(true);
}
void EasyDescWidget::findNext(bool)
{
auto matches = m_tree->findNext(m_searchBox->text(), m_bCaseSensitiveSearch ? Qt::MatchCaseSensitive : Qt::MatchFlags());
if (matches == 1)
m_foundNumber->setText(QString("Found 1 match"));
else
m_foundNumber->setText(QString("Found %1 matches").arg(matches));
}
void EasyDescWidget::findPrev(bool)
{
auto matches = m_tree->findPrev(m_searchBox->text(), m_bCaseSensitiveSearch ? Qt::MatchCaseSensitive : Qt::MatchFlags());
if (matches == 1)
m_foundNumber->setText(QString("Found 1 match"));
else
m_foundNumber->setText(QString("Found %1 matches").arg(matches));
}
void EasyDescWidget::findNextFromMenu(bool _checked)
{
if (!_checked)
return;
if (m_searchButton->data().toBool() == false)
{
m_searchButton->setData(true);
m_searchButton->setText(tr("Find next"));
m_searchButton->setIcon(QIcon(":/Search-next"));
disconnect(m_searchButton, &QAction::triggered, this, &This::findPrev);
connect(m_searchButton, &QAction::triggered, this, &This::findNext);
}
findNext(true);
}
void EasyDescWidget::findPrevFromMenu(bool _checked)
{
if (!_checked)
return;
if (m_searchButton->data().toBool() == true)
{
m_searchButton->setData(false);
m_searchButton->setText(tr("Find prev"));
m_searchButton->setIcon(QIcon(":/Search-prev"));
disconnect(m_searchButton, &QAction::triggered, this, &This::findNext);
connect(m_searchButton, &QAction::triggered, this, &This::findPrev);
}
findPrev(true);
}
//////////////////////////////////////////////////////////////////////////

View File

@ -0,0 +1,199 @@
/************************************************************************
* file name : descriptors_tree_widget.h
* ----------------- :
* creation time : 2016/09/17
* author : Victor Zarubkin
* email : v.s.zarubkin@gmail.com
* ----------------- :
* description : The file contains declaration of EasyDescTreeWidget and it's auxiliary classes
* : for displyaing EasyProfiler blocks descriptors tree.
* ----------------- :
* change log : * 2016/09/17 Victor Zarubkin: initial commit.
* :
* : *
* ----------------- :
* license : Lightweight profiler library for c++
* : Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
* :
* :
* : Licensed under the Apache License, Version 2.0 (the "License");
* : you may not use this file except in compliance with the License.
* : You may obtain a copy of the License at
* :
* : http://www.apache.org/licenses/LICENSE-2.0
* :
* : Unless required by applicable law or agreed to in writing, software
* : distributed under the License is distributed on an "AS IS" BASIS,
* : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* : See the License for the specific language governing permissions and
* : limitations under the License.
* :
* :
* : GNU General Public License Usage
* : Alternatively, this file may be used under the terms of the GNU
* : General Public License as published by the Free Software Foundation,
* : either version 3 of the License, or (at your option) any later version.
* :
* : This program is distributed in the hope that it will be useful,
* : but WITHOUT ANY WARRANTY; without even the implied warranty of
* : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
* : GNU General Public License for more details.
* :
* : You should have received a copy of the GNU General Public License
* : along with this program.If not, see <http://www.gnu.org/licenses/>.
************************************************************************/
#ifndef EASY__DESCRIPTORS__WIDGET__H_
#define EASY__DESCRIPTORS__WIDGET__H_
#include <QTreeWidget>
#include <QString>
#include <vector>
#include <unordered_set>
#include "easy/profiler.h"
//////////////////////////////////////////////////////////////////////////
class EasyDescWidgetItem : public QTreeWidgetItem
{
typedef QTreeWidgetItem Parent;
typedef EasyDescWidgetItem This;
::profiler::block_id_t m_desc;
public:
explicit EasyDescWidgetItem(::profiler::block_id_t _desc, Parent* _parent = nullptr);
virtual ~EasyDescWidgetItem();
bool operator < (const Parent& _other) const override;
public:
// Public inline methods
inline ::profiler::block_id_t desc() const
{
return m_desc;
}
}; // END of class EasyDescWidgetItem.
//////////////////////////////////////////////////////////////////////////
class EasyDescTreeWidget : public QTreeWidget
{
Q_OBJECT
typedef QTreeWidget Parent;
typedef EasyDescTreeWidget This;
typedef ::std::vector<EasyDescWidgetItem*> Items;
typedef ::std::vector<QTreeWidgetItem*> TreeItems;
typedef ::std::unordered_set<::std::string> ExpandedFiles;
protected:
ExpandedFiles m_expandedFilesTemp;
Items m_items;
TreeItems m_highlightItems;
QString m_lastSearch;
QTreeWidgetItem* m_lastFound;
int m_lastSearchColumn;
int m_searchColumn;
bool m_bLocked;
public:
// Public virtual methods
explicit EasyDescTreeWidget(QWidget* _parent = nullptr);
virtual ~EasyDescTreeWidget();
void contextMenuEvent(QContextMenuEvent* _event) override;
public:
// Public non-virtual methods
int findNext(const QString& _str, Qt::MatchFlags _flags);
int findPrev(const QString& _str, Qt::MatchFlags _flags);
public slots:
void clearSilent(bool _global = false);
void build();
private slots:
void onSearchColumnChange(bool);
void onBlockStatusChangeClicked(bool);
void onCurrentItemChange(QTreeWidgetItem* _item, QTreeWidgetItem* _prev);
void onItemExpand(QTreeWidgetItem* _item);
void onDoubleClick(QTreeWidgetItem* _item, int _column);
void onSelectedBlockChange(uint32_t _block_index);
void onBlockStatusChange(::profiler::block_id_t _id, ::profiler::EasyBlockStatus _status);
void resizeColumnsToContents();
private:
// Private methods
void resetHighlight();
void loadSettings();
void saveSettings();
}; // END of class EasyDescTreeWidget.
//////////////////////////////////////////////////////////////////////////
class EasyDescWidget : public QWidget
{
Q_OBJECT
typedef QWidget Parent;
typedef EasyDescWidget This;
private:
EasyDescTreeWidget* m_tree;
class QLineEdit* m_searchBox;
class QLabel* m_foundNumber;
class QAction* m_searchButton;
bool m_bCaseSensitiveSearch;
public:
// Public virtual methods
explicit EasyDescWidget(QWidget* _parent = nullptr);
virtual ~EasyDescWidget();
void keyPressEvent(QKeyEvent* _event) override;
void contextMenuEvent(QContextMenuEvent* _event) override;
public:
// Public non-virtual methods
void build();
void clear();
private slots:
void onSeachBoxReturnPressed();
void findNext(bool);
void findPrev(bool);
void findNextFromMenu(bool);
void findPrevFromMenu(bool);
private:
// Private non-virtual slots
void loadSettings();
void saveSettings();
}; // END of class EasyDescWidget.
//////////////////////////////////////////////////////////////////////////
#endif // EASY__DESCRIPTORS__WIDGET__H_

View File

@ -0,0 +1,305 @@
/************************************************************************
* file name : easy_chronometer_item.cpp
* ----------------- :
* creation time : 2016/09/15
* author : Victor Zarubkin
* email : v.s.zarubkin@gmail.com
* ----------------- :
* description : The file contains implementation of EasyChronometerItem.
* ----------------- :
* change log : * 2016/09/15 Victor Zarubkin: moved sources from blocks_graphics_view.cpp
* :
* : *
* ----------------- :
* license : Lightweight profiler library for c++
* : Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
* :
* :
* : Licensed under the Apache License, Version 2.0 (the "License");
* : you may not use this file except in compliance with the License.
* : You may obtain a copy of the License at
* :
* : http://www.apache.org/licenses/LICENSE-2.0
* :
* : Unless required by applicable law or agreed to in writing, software
* : distributed under the License is distributed on an "AS IS" BASIS,
* : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* : See the License for the specific language governing permissions and
* : limitations under the License.
* :
* :
* : GNU General Public License Usage
* : Alternatively, this file may be used under the terms of the GNU
* : General Public License as published by the Free Software Foundation,
* : either version 3 of the License, or (at your option) any later version.
* :
* : This program is distributed in the hope that it will be useful,
* : but WITHOUT ANY WARRANTY; without even the implied warranty of
* : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
* : GNU General Public License for more details.
* :
* : You should have received a copy of the GNU General Public License
* : along with this program.If not, see <http://www.gnu.org/licenses/>.
************************************************************************/
#include <QGraphicsScene>
#include <QFontMetricsF>
#include "blocks_graphics_view.h"
#include "easy_chronometer_item.h"
#include "globals.h"
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
const auto CHRONOMETER_FONT = ::profiler_gui::EFont("Helvetica", 16, QFont::Bold);
#ifdef max
#undef max
#endif
#ifdef min
#undef min
#endif
//////////////////////////////////////////////////////////////////////////
EasyChronometerItem::EasyChronometerItem(bool _main)
: QGraphicsItem()
, m_color(::profiler_gui::CHRONOMETER_COLOR)
, m_left(0)
, m_right(0)
, m_bMain(_main)
, m_bReverse(false)
, m_bHoverIndicator(false)
{
m_indicator.reserve(3);
}
EasyChronometerItem::~EasyChronometerItem()
{
}
QRectF EasyChronometerItem::boundingRect() const
{
return m_boundingRect;
}
void EasyChronometerItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem*, QWidget*)
{
auto const sceneView = view();
const auto currentScale = sceneView->scale();
const auto offset = sceneView->offset();
const auto visibleSceneRect = sceneView->visibleSceneRect();
auto sceneLeft = offset, sceneRight = offset + visibleSceneRect.width() / currentScale;
if (m_bMain)
m_indicator.clear();
if (m_left > sceneRight || m_right < sceneLeft)
{
// This item is out of screen
if (m_bMain)
{
const int size = m_bHoverIndicator ? 12 : 10;
auto vcenter = visibleSceneRect.top() + visibleSceneRect.height() * 0.5;
auto color = QColor::fromRgb(m_color.rgb());
auto pen = _painter->pen();
pen.setColor(color);
m_indicator.clear();
if (m_left > sceneRight)
{
sceneRight = (sceneRight - offset) * currentScale;
m_indicator.push_back(QPointF(sceneRight - size, vcenter - size));
m_indicator.push_back(QPointF(sceneRight, vcenter));
m_indicator.push_back(QPointF(sceneRight - size, vcenter + size));
}
else
{
sceneLeft = (sceneLeft - offset) * currentScale;
m_indicator.push_back(QPointF(sceneLeft + size, vcenter - size));
m_indicator.push_back(QPointF(sceneLeft, vcenter));
m_indicator.push_back(QPointF(sceneLeft + size, vcenter + size));
}
_painter->save();
_painter->setTransform(QTransform::fromTranslate(-x(), -y()), true);
_painter->setBrush(m_bHoverIndicator ? QColor::fromRgb(0xffff0000) : color);
_painter->setPen(pen);
_painter->drawPolygon(m_indicator);
_painter->restore();
}
return;
}
auto selectedInterval = width();
QRectF rect((m_left - offset) * currentScale, visibleSceneRect.top(), ::std::max(selectedInterval * currentScale, 1.0), visibleSceneRect.height());
selectedInterval = units2microseconds(selectedInterval);
const QString text = ::profiler_gui::timeStringReal(EASY_GLOBALS.time_units, selectedInterval); // Displayed text
const auto textRect = QFontMetricsF(CHRONOMETER_FONT, sceneView).boundingRect(text); // Calculate displayed text boundingRect
const auto rgb = m_color.rgb() & 0x00ffffff;
// Paint!--------------------------
_painter->save();
// instead of scrollbar we're using manual offset
_painter->setTransform(QTransform::fromTranslate(-x(), -y()), true);
if (m_left < sceneLeft)
rect.setLeft(0);
if (m_right > sceneRight)
rect.setWidth((sceneRight - offset) * currentScale - rect.left());
// draw transparent rectangle
auto vcenter = rect.top() + rect.height() * 0.5;
QLinearGradient g(rect.left(), vcenter, rect.right(), vcenter);
g.setColorAt(0, m_color);
g.setColorAt(0.2, QColor::fromRgba(0x14000000 | rgb));
g.setColorAt(0.8, QColor::fromRgba(0x14000000 | rgb));
g.setColorAt(1, m_color);
_painter->setBrush(g);
_painter->setPen(Qt::NoPen);
_painter->drawRect(rect);
// draw left and right borders
_painter->setBrush(Qt::NoBrush);
if (m_bMain && !m_bReverse)
{
QPen p(QColor::fromRgba(0xd0000000 | rgb));
p.setStyle(Qt::DotLine);
_painter->setPen(p);
}
else
{
_painter->setPen(QColor::fromRgba(0xd0000000 | rgb));
}
if (m_left > sceneLeft)
_painter->drawLine(QPointF(rect.left(), rect.top()), QPointF(rect.left(), rect.bottom()));
if (m_right < sceneRight)
_painter->drawLine(QPointF(rect.right(), rect.top()), QPointF(rect.right(), rect.bottom()));
// draw text
_painter->setCompositionMode(QPainter::CompositionMode_Difference); // This lets the text to be visible on every background
_painter->setRenderHint(QPainter::TextAntialiasing);
_painter->setPen(0x00ffffff - rgb);
_painter->setFont(CHRONOMETER_FONT);
int textFlags = 0;
switch (EASY_GLOBALS.chrono_text_position)
{
case ::profiler_gui::ChronoTextPosition_Top:
textFlags = Qt::AlignTop | Qt::AlignHCenter;
if (!m_bMain) rect.setTop(rect.top() + textRect.height() * 0.75);
break;
case ::profiler_gui::ChronoTextPosition_Center:
textFlags = Qt::AlignCenter;
if (!m_bMain) rect.setTop(rect.top() + textRect.height() * 1.5);
break;
case ::profiler_gui::ChronoTextPosition_Bottom:
textFlags = Qt::AlignBottom | Qt::AlignHCenter;
if (!m_bMain) rect.setHeight(rect.height() - textRect.height() * 0.75);
break;
}
const auto textRect_width = textRect.width() * ::profiler_gui::FONT_METRICS_FACTOR;
if (textRect_width < rect.width())
{
// Text will be drawed inside rectangle
_painter->drawText(rect, textFlags, text);
_painter->restore();
return;
}
const auto w = textRect_width / currentScale;
if (m_right + w < sceneRight)
{
// Text will be drawed to the right of rectangle
rect.translate(rect.width(), 0);
textFlags &= ~Qt::AlignHCenter;
textFlags |= Qt::AlignLeft;
}
else if (m_left - w > sceneLeft)
{
// Text will be drawed to the left of rectangle
rect.translate(-rect.width(), 0);
textFlags &= ~Qt::AlignHCenter;
textFlags |= Qt::AlignRight;
}
//else // Text will be drawed inside rectangle
_painter->drawText(rect, textFlags | Qt::TextDontClip, text);
_painter->restore();
// END Paint!~~~~~~~~~~~~~~~~~~~~~~
}
bool EasyChronometerItem::contains(const QPointF& _pos) const
{
const auto sceneView = view();
const auto clickX = (_pos.x() - sceneView->offset()) * sceneView->scale() - x();
if (!m_indicator.empty() && m_indicator.containsPoint(QPointF(clickX, _pos.y()), Qt::OddEvenFill))
return true;
return false;
}
void EasyChronometerItem::setColor(const QColor& _color)
{
m_color = _color;
}
void EasyChronometerItem::setBoundingRect(qreal x, qreal y, qreal w, qreal h)
{
m_boundingRect.setRect(x, y, w, h);
}
void EasyChronometerItem::setBoundingRect(const QRectF& _rect)
{
m_boundingRect = _rect;
}
void EasyChronometerItem::setLeftRight(qreal _left, qreal _right)
{
if (_left < _right)
{
m_left = _left;
m_right = _right;
}
else
{
m_left = _right;
m_right = _left;
}
}
void EasyChronometerItem::setReverse(bool _reverse)
{
m_bReverse = _reverse;
}
void EasyChronometerItem::setHover(bool _hover)
{
m_bHoverIndicator = _hover;
}
const EasyGraphicsView* EasyChronometerItem::view() const
{
return static_cast<const EasyGraphicsView*>(scene()->parent());
}
EasyGraphicsView* EasyChronometerItem::view()
{
return static_cast<EasyGraphicsView*>(scene()->parent());
}
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////

View File

@ -0,0 +1,135 @@
/************************************************************************
* file name : easy_chronometer_item.h
* ----------------- :
* creation time : 2016/09/15
* author : Victor Zarubkin
* email : v.s.zarubkin@gmail.com
* ----------------- :
* description : The file contains declaration of EasyChronometerItem - an item
* : used to display selected interval on graphics scene.
* ----------------- :
* change log : * 2016/09/15 Victor Zarubkin: moved sources from blocks_graphics_view.h
* :
* : *
* ----------------- :
* license : Lightweight profiler library for c++
* : Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
* :
* :
* : Licensed under the Apache License, Version 2.0 (the "License");
* : you may not use this file except in compliance with the License.
* : You may obtain a copy of the License at
* :
* : http://www.apache.org/licenses/LICENSE-2.0
* :
* : Unless required by applicable law or agreed to in writing, software
* : distributed under the License is distributed on an "AS IS" BASIS,
* : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* : See the License for the specific language governing permissions and
* : limitations under the License.
* :
* :
* : GNU General Public License Usage
* : Alternatively, this file may be used under the terms of the GNU
* : General Public License as published by the Free Software Foundation,
* : either version 3 of the License, or (at your option) any later version.
* :
* : This program is distributed in the hope that it will be useful,
* : but WITHOUT ANY WARRANTY; without even the implied warranty of
* : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
* : GNU General Public License for more details.
* :
* : You should have received a copy of the GNU General Public License
* : along with this program.If not, see <http://www.gnu.org/licenses/>.
************************************************************************/
#ifndef EASY__CHRONOMETER_ITEM__H_
#define EASY__CHRONOMETER_ITEM__H_
#include <QGraphicsItem>
#include <QRectF>
#include <QPolygonF>
#include <QColor>
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
class QWidget;
class QPainter;
class QStyleOptionGraphicsItem;
class EasyGraphicsView;
class EasyChronometerItem : public QGraphicsItem
{
QPolygonF m_indicator; ///< Indicator displayed when this chrono item is out of screen (displaying only for main item)
QRectF m_boundingRect; ///< boundingRect (see QGraphicsItem)
QColor m_color; ///< Color of the item
qreal m_left, m_right; ///< Left and right bounds of the selection zone
bool m_bMain; ///< Is this chronometer main (true, by default)
bool m_bReverse; ///<
bool m_bHoverIndicator; ///< Mouse hover above indicator
public:
explicit EasyChronometerItem(bool _main = true);
virtual ~EasyChronometerItem();
// Public virtual methods
QRectF boundingRect() const override;
void paint(QPainter* _painter, const QStyleOptionGraphicsItem* _option, QWidget* _widget = nullptr) override;
public:
// Public non-virtual methods
void setColor(const QColor& _color);
void setBoundingRect(qreal x, qreal y, qreal w, qreal h);
void setBoundingRect(const QRectF& _rect);
void setLeftRight(qreal _left, qreal _right);
void setReverse(bool _reverse);
void setHover(bool _hover);
bool contains(const QPointF& _pos) const override;
inline bool hoverIndicator() const
{
return m_bHoverIndicator;
}
inline bool reverse() const
{
return m_bReverse;
}
inline qreal left() const
{
return m_left;
}
inline qreal right() const
{
return m_right;
}
inline qreal width() const
{
return m_right - m_left;
}
private:
///< Returns pointer to the EasyGraphicsView widget.
const EasyGraphicsView* view() const;
EasyGraphicsView* view();
}; // END of class EasyChronometerItem.
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
#endif // EASY__CHRONOMETER_ITEM__H_

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,182 @@
/************************************************************************
* file name : easy_graphics_item.h
* ----------------- :
* creation time : 2016/09/15
* author : Victor Zarubkin
* email : v.s.zarubkin@gmail.com
* ----------------- :
* description : The file contains declaration of EasyGraphicsItem - an item
* : used to draw profiler blocks on graphics scene.
* ----------------- :
* change log : * 2016/09/15 Victor Zarubkin: moved sources from blocks_graphics_view.h/.cpp
* :
* : *
* ----------------- :
* license : Lightweight profiler library for c++
* : Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
* :
* :
* : Licensed under the Apache License, Version 2.0 (the "License");
* : you may not use this file except in compliance with the License.
* : You may obtain a copy of the License at
* :
* : http://www.apache.org/licenses/LICENSE-2.0
* :
* : Unless required by applicable law or agreed to in writing, software
* : distributed under the License is distributed on an "AS IS" BASIS,
* : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* : See the License for the specific language governing permissions and
* : limitations under the License.
* :
* :
* : GNU General Public License Usage
* : Alternatively, this file may be used under the terms of the GNU
* : General Public License as published by the Free Software Foundation,
* : either version 3 of the License, or (at your option) any later version.
* :
* : This program is distributed in the hope that it will be useful,
* : but WITHOUT ANY WARRANTY; without even the implied warranty of
* : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
* : GNU General Public License for more details.
* :
* : You should have received a copy of the GNU General Public License
* : along with this program.If not, see <http://www.gnu.org/licenses/>.
************************************************************************/
#ifndef EASY__GRAPHICS_ITEM__H_
#define EASY__GRAPHICS_ITEM__H_
#include <stdlib.h>
#include <QGraphicsItem>
#include <QRectF>
#include <QString>
#include "easy/reader.h"
#include "common_types.h"
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
class EasyGraphicsView;
class EasyGraphicsItem : public QGraphicsItem
{
typedef ::profiler_gui::EasyItems Children;
typedef ::std::vector<uint32_t> DrawIndexes;
typedef ::std::vector<qreal> RightBounds;
typedef ::std::vector<Children> Sublevels;
DrawIndexes m_levelsIndexes; ///< Indexes of first item on each level from which we must start painting
RightBounds m_rightBounds; ///<
Sublevels m_levels; ///< Arrays of items for each level
QRectF m_boundingRect; ///< boundingRect (see QGraphicsItem)
QString m_threadName; ///<
const ::profiler::BlocksTreeRoot* m_pRoot; ///< Pointer to the root profiler block (thread block). Used by ProfTreeWidget to restore hierarchy.
uint8_t m_index; ///< This item's index in the list of items of EasyGraphicsView
public:
explicit EasyGraphicsItem(uint8_t _index, const::profiler::BlocksTreeRoot& _root);
virtual ~EasyGraphicsItem();
// Public virtual methods
QRectF boundingRect() const override;
void paint(QPainter* _painter, const QStyleOptionGraphicsItem* _option, QWidget* _widget = nullptr) override;
public:
// Public non-virtual methods
void validateName();
const ::profiler::BlocksTreeRoot* root() const;
const QString& threadName() const;
QRect getRect() const;
void setBoundingRect(qreal x, qreal y, qreal w, qreal h);
void setBoundingRect(const QRectF& _rect);
::profiler::thread_id_t threadId() const;
///< Returns number of levels
uint8_t levels() const;
float levelY(uint8_t _level) const;
/** \brief Sets number of levels.
\note Must be set before doing anything else.
\param _levels Desired number of levels */
void setLevels(uint8_t _levels);
/** \brief Reserves memory for desired number of items on specified level.
\param _level Index of the level
\param _items Desired number of items on this level */
void reserve(uint8_t _level, unsigned int _items);
/**\brief Returns reference to the array of items of specified level.
\param _level Index of the level */
const Children& items(uint8_t _level) const;
/**\brief Returns reference to the item with required index on specified level.
\param _level Index of the level
\param _index Index of required item */
const ::profiler_gui::EasyBlockItem& getItem(uint8_t _level, unsigned int _index) const;
/**\brief Returns reference to the item with required index on specified level.
\param _level Index of the level
\param _index Index of required item */
::profiler_gui::EasyBlockItem& getItem(uint8_t _level, unsigned int _index);
/** \brief Adds new item to required level.
\param _level Index of the level
\retval Index of the new created item */
unsigned int addItem(uint8_t _level);
/** \brief Finds top-level blocks which are intersects with required selection zone.
\note Found blocks will be added into the array of selected blocks.
\param _left Left bound of the selection zone
\param _right Right bound of the selection zone
\param _blocks Reference to the array of selected blocks */
void getBlocks(qreal _left, qreal _right, ::profiler_gui::TreeBlocks& _blocks) const;
const ::profiler_gui::EasyBlock* intersect(const QPointF& _pos, ::profiler::block_index_t& _blockIndex) const;
const ::profiler_gui::EasyBlock* intersectEvent(const QPointF& _pos) const;
private:
///< Returns pointer to the EasyGraphicsView widget.
const EasyGraphicsView* view() const;
#ifdef EASY_GRAPHICS_ITEM_RECURSIVE_PAINT
void paintChildren(const float _minWidth, const int _narrowSizeHalf, const uint8_t _levelsNumber, QPainter* _painter, struct EasyPainterInformation& p, ::profiler_gui::EasyBlockItem& _item, const ::profiler_gui::EasyBlock& _itemBlock, RightBounds& _rightBounds, uint8_t _level, int8_t _mode);
#endif
public:
// Public inline methods
///< Returns this item's index in the list of graphics items of EasyGraphicsView
inline uint8_t index() const
{
return m_index;
}
}; // END of class EasyGraphicsItem.
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
#endif // EASY__GRAPHICS_ITEM__H_

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,296 @@
/************************************************************************
* file name : easy_graphics_scrollbar.h
* ----------------- :
* creation time : 2016/07/04
* author : Victor Zarubkin
* email : v.s.zarubkin@gmail.com
* ----------------- :
* description : This file contains declaration of
* ----------------- :
* change log : * 2016/07/04 Victor Zarubkin: Initial commit.
* :
* : *
* ----------------- :
* license : Lightweight profiler library for c++
* : Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
* :
* :
* : Licensed under the Apache License, Version 2.0 (the "License");
* : you may not use this file except in compliance with the License.
* : You may obtain a copy of the License at
* :
* : http://www.apache.org/licenses/LICENSE-2.0
* :
* : Unless required by applicable law or agreed to in writing, software
* : distributed under the License is distributed on an "AS IS" BASIS,
* : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* : See the License for the specific language governing permissions and
* : limitations under the License.
* :
* :
* : GNU General Public License Usage
* : Alternatively, this file may be used under the terms of the GNU
* : General Public License as published by the Free Software Foundation,
* : either version 3 of the License, or (at your option) any later version.
* :
* : This program is distributed in the hope that it will be useful,
* : but WITHOUT ANY WARRANTY; without even the implied warranty of
* : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
* : GNU General Public License for more details.
* :
* : You should have received a copy of the GNU General Public License
* : along with this program.If not, see <http://www.gnu.org/licenses/>.
************************************************************************/
#ifndef EASY__GRAPHICS_SCROLLBAR__H
#define EASY__GRAPHICS_SCROLLBAR__H
#include <stdlib.h>
#include <thread>
#include <atomic>
#include <QGraphicsView>
#include <QGraphicsRectItem>
#include <QAction>
#include <QPolygonF>
#include <QImage>
#include "easy_qtimer.h"
#include "common_types.h"
//////////////////////////////////////////////////////////////////////////
// TODO: use profiler_core/spin_lock.h
#define EASY_GUI_USE_CRITICAL_SECTION // Use CRITICAL_SECTION instead of std::atomic_flag
#if defined(_WIN32) && defined(EASY_GUI_USE_CRITICAL_SECTION)
namespace profiler_gui {
// std::atomic_flag on Windows works slower than critical section, so we will use it instead of std::atomic_flag...
// By the way, Windows critical sections are slower than std::atomic_flag on Unix.
class spin_lock { void* m_lock; public:
void lock();
void unlock();
spin_lock();
~spin_lock();
};
#else
namespace profiler_gui {
// std::atomic_flag on Unix works fine and very fast (almost instant!)
class spin_lock {
::std::atomic_flag m_lock; public:
void lock() {
while (m_lock.test_and_set(::std::memory_order_acquire));
}
void unlock() {
m_lock.clear(::std::memory_order_release);
}
spin_lock() {
m_lock.clear();
}
};
#endif
} // END of namespace profiler_gui.
//////////////////////////////////////////////////////////////////////////
class EasyGraphicsSliderItem : public QGraphicsRectItem
{
typedef QGraphicsRectItem Parent;
typedef EasyGraphicsSliderItem This;
private:
QPolygonF m_indicator;
qreal m_halfwidth;
bool m_bMain;
public:
explicit EasyGraphicsSliderItem(bool _main);
virtual ~EasyGraphicsSliderItem();
void paint(QPainter* _painter, const QStyleOptionGraphicsItem* _option, QWidget* _widget = nullptr) override;
qreal width() const;
qreal halfwidth() const;
void setWidth(qreal _width);
void setHalfwidth(qreal _halfwidth);
void setColor(QRgb _color);
void setColor(const QColor& _color);
}; // END of class EasyGraphicsSliderItem.
//////////////////////////////////////////////////////////////////////////
class EasyHystogramItem : public QGraphicsItem
{
typedef QGraphicsItem Parent;
typedef EasyHystogramItem This;
enum HystRegime : uint8_t { Hyst_Pointer, Hyst_Id };
QRectF m_boundingRect;
qreal m_maxDuration;
qreal m_minDuration;
QString m_maxDurationStr;
QString m_minDurationStr;
QString m_threadName;
::profiler::BlocksTree::children_t m_selectedBlocks;
QImage m_mainImage;
EasyQTimer m_timer;
::std::thread m_workerThread;
::profiler::timestamp_t m_threadDuration;
::profiler::timestamp_t m_threadProfiledTime;
::profiler::timestamp_t m_threadWaitTime;
const ::profiler_gui::EasyItems* m_pSource;
QImage* m_temporaryImage;
const ::profiler::BlocksTreeRoot* m_pProfilerThread;
::profiler::thread_id_t m_threadId;
::profiler::block_index_t m_blockId;
int m_timeouts;
::profiler_gui::TimeUnits m_timeUnits;
HystRegime m_regime;
bool m_bUpdatingImage;
::profiler_gui::spin_lock m_spin;
::std::atomic_bool m_bReady;
public:
explicit EasyHystogramItem();
virtual ~EasyHystogramItem();
// Public virtual methods
QRectF boundingRect() const override;
void paint(QPainter* _painter, const QStyleOptionGraphicsItem* _option, QWidget* _widget = nullptr) override;
public:
// Public non-virtual methods
::profiler::thread_id_t threadId() const;
void setBoundingRect(const QRectF& _rect);
void setBoundingRect(qreal x, qreal y, qreal w, qreal h);
void setSource(::profiler::thread_id_t _thread_id, const ::profiler_gui::EasyItems* _items);
void setSource(::profiler::thread_id_t _thread_id, ::profiler::block_id_t _block_id);
void validateName();
void updateImage();
private:
void paintByPtr(QPainter* _painter);
void paintById(QPainter* _painter);
void onTimeout();
void updateImage(HystRegime _regime, qreal _current_scale,
qreal _minimum, qreal _maximum, qreal _range,
qreal _value, qreal _width, bool _bindMode,
float _frame_time, ::profiler::timestamp_t _begin_time);
}; // END of class EasyHystogramItem.
//////////////////////////////////////////////////////////////////////////
class EasyGraphicsScrollbar : public QGraphicsView
{
Q_OBJECT
private:
typedef QGraphicsView Parent;
typedef EasyGraphicsScrollbar This;
qreal m_minimumValue;
qreal m_maximumValue;
qreal m_value;
qreal m_windowScale;
QPoint m_mousePressPos;
Qt::MouseButtons m_mouseButtons;
EasyGraphicsSliderItem* m_slider;
EasyGraphicsSliderItem* m_chronometerIndicator;
EasyHystogramItem* m_hystogramItem;
int m_defaultFontHeight;
bool m_bScrolling;
bool m_bBindMode;
bool m_bLocked;
public:
explicit EasyGraphicsScrollbar(QWidget* _parent = nullptr);
virtual ~EasyGraphicsScrollbar();
// Public virtual methods
void mousePressEvent(QMouseEvent* _event) override;
void mouseReleaseEvent(QMouseEvent* _event) override;
void mouseMoveEvent(QMouseEvent* _event) override;
void wheelEvent(QWheelEvent* _event) override;
void resizeEvent(QResizeEvent* _event) override;
//void contextMenuEvent(QContextMenuEvent* _event) override;
void dragEnterEvent(QDragEnterEvent*) override {}
public:
// Public non-virtual methods
void clear();
bool bindMode() const;
qreal getWindowScale() const;
::profiler::thread_id_t hystThread() const;
qreal minimum() const;
qreal maximum() const;
qreal range() const;
qreal value() const;
qreal sliderWidth() const;
qreal sliderHalfWidth() const;
int defaultFontHeight() const;
void setValue(qreal _value);
void setRange(qreal _minValue, qreal _maxValue);
void setSliderWidth(qreal _width);
void setChronoPos(qreal _left, qreal _right);
void showChrono();
void hideChrono();
void setHystogramFrom(::profiler::thread_id_t _thread_id, const::profiler_gui::EasyItems* _items);
void setHystogramFrom(::profiler::thread_id_t _thread_id, ::profiler::block_id_t _block_id);
inline void setHystogramFrom(::profiler::thread_id_t _thread_id, const ::profiler_gui::EasyItems& _items)
{
setHystogramFrom(_thread_id, &_items);
}
inline void lock()
{
m_bLocked = true;
}
inline void unlock()
{
m_bLocked = false;
}
signals:
void rangeChanged();
void valueChanged(qreal _value);
void wheeled(qreal _mouseX, int _wheelDelta);
private slots:
void onThreadActionClicked(bool);
void onWindowWidthChange(qreal _width);
}; // END of class EasyGraphicsScrollbar.
//////////////////////////////////////////////////////////////////////////
#endif // EASY__GRAPHICS_SCROLLBAR__H

View File

@ -0,0 +1,74 @@
/************************************************************************
* file name : easy_qtimer.h
* ----------------- :
* creation time : 2016/12/05
* author : Victor Zarubkin
* email : v.s.zarubkin@gmail.com
* ----------------- :
* description : This file contains implementation of EasyQTimer class used to
* : connect QTimer to non-QObject classes.
* ----------------- :
* change log : * 2016/12/05 Victor Zarubkin: Initial commit.
* :
* : *
* ----------------- :
* license : Lightweight profiler library for c++
* : Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
* :
* :
* : Licensed under the Apache License, Version 2.0 (the "License");
* : you may not use this file except in compliance with the License.
* : You may obtain a copy of the License at
* :
* : http://www.apache.org/licenses/LICENSE-2.0
* :
* : Unless required by applicable law or agreed to in writing, software
* : distributed under the License is distributed on an "AS IS" BASIS,
* : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* : See the License for the specific language governing permissions and
* : limitations under the License.
* :
* :
* : GNU General Public License Usage
* : Alternatively, this file may be used under the terms of the GNU
* : General Public License as published by the Free Software Foundation,
* : either version 3 of the License, or (at your option) any later version.
* :
* : This program is distributed in the hope that it will be useful,
* : but WITHOUT ANY WARRANTY; without even the implied warranty of
* : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
* : GNU General Public License for more details.
* :
* : You should have received a copy of the GNU General Public License
* : along with this program.If not, see <http://www.gnu.org/licenses/>.
************************************************************************/
#include "easy_qtimer.h"
//////////////////////////////////////////////////////////////////////////
EasyQTimer::EasyQTimer()
: QObject()
{
connect(&m_timer, &QTimer::timeout, [this](){ m_handler(); });
}
EasyQTimer::EasyQTimer(::std::function<void()>&& _handler)
: QObject()
, m_handler(::std::forward<::std::function<void()>&&>(_handler))
{
connect(&m_timer, &QTimer::timeout, [this](){ m_handler(); });
}
EasyQTimer::~EasyQTimer()
{
}
void EasyQTimer::setHandler(::std::function<void()>&& _handler)
{
m_handler = _handler;
}
//////////////////////////////////////////////////////////////////////////

View File

@ -0,0 +1,79 @@
/************************************************************************
* file name : easy_qtimer.h
* ----------------- :
* creation time : 2016/12/05
* author : Victor Zarubkin
* email : v.s.zarubkin@gmail.com
* ----------------- :
* description : This file contains declaration of EasyQTimer class used to
* : connect QTimer to non-QObject classes.
* ----------------- :
* change log : * 2016/12/05 Victor Zarubkin: Initial commit.
* :
* : *
* ----------------- :
* license : Lightweight profiler library for c++
* : Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
* :
* :
* : Licensed under the Apache License, Version 2.0 (the "License");
* : you may not use this file except in compliance with the License.
* : You may obtain a copy of the License at
* :
* : http://www.apache.org/licenses/LICENSE-2.0
* :
* : Unless required by applicable law or agreed to in writing, software
* : distributed under the License is distributed on an "AS IS" BASIS,
* : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* : See the License for the specific language governing permissions and
* : limitations under the License.
* :
* :
* : GNU General Public License Usage
* : Alternatively, this file may be used under the terms of the GNU
* : General Public License as published by the Free Software Foundation,
* : either version 3 of the License, or (at your option) any later version.
* :
* : This program is distributed in the hope that it will be useful,
* : but WITHOUT ANY WARRANTY; without even the implied warranty of
* : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
* : GNU General Public License for more details.
* :
* : You should have received a copy of the GNU General Public License
* : along with this program.If not, see <http://www.gnu.org/licenses/>.
************************************************************************/
#ifndef EASY__QTIMER__H
#define EASY__QTIMER__H
#include <QTimer>
#include <functional>
//////////////////////////////////////////////////////////////////////////
class EasyQTimer : public QObject
{
Q_OBJECT
private:
QTimer m_timer;
::std::function<void()> m_handler;
public:
EasyQTimer();
EasyQTimer(::std::function<void()>&& _handler);
virtual ~EasyQTimer();
void setHandler(::std::function<void()>&& _handler);
inline void start(int msec) { m_timer.start(msec); }
inline void stop() { m_timer.stop(); }
inline bool isActive() const { return m_timer.isActive(); }
}; // END of class EasyQTimer.
//////////////////////////////////////////////////////////////////////////
#endif // EASY__QTIMER__H

View File

@ -0,0 +1,95 @@
/************************************************************************
* file name : globals.cpp
* ----------------- :
* creation time : 2016/08/03
* author : Victor Zarubkin
* email : v.s.zarubkin@gmail.com
* ----------------- :
* description : The file contains implementation of global constants and variables for profiler gui.
* ----------------- :
* change log : * 2016/08/03 Victor Zarubkin: initial commit.
* :
* : *
* ----------------- :
* license : Lightweight profiler library for c++
* : Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
* :
* :
* : Licensed under the Apache License, Version 2.0 (the "License");
* : you may not use this file except in compliance with the License.
* : You may obtain a copy of the License at
* :
* : http://www.apache.org/licenses/LICENSE-2.0
* :
* : Unless required by applicable law or agreed to in writing, software
* : distributed under the License is distributed on an "AS IS" BASIS,
* : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* : See the License for the specific language governing permissions and
* : limitations under the License.
* :
* :
* : GNU General Public License Usage
* : Alternatively, this file may be used under the terms of the GNU
* : General Public License as published by the Free Software Foundation,
* : either version 3 of the License, or (at your option) any later version.
* :
* : This program is distributed in the hope that it will be useful,
* : but WITHOUT ANY WARRANTY; without even the implied warranty of
* : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
* : GNU General Public License for more details.
* :
* : You should have received a copy of the GNU General Public License
* : along with this program.If not, see <http://www.gnu.org/licenses/>.
************************************************************************/
#define IGNORE_GLOBALS_DECLARATION
#include "globals.h"
#undef IGNORE_GLOBALS_DECLARATION
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
namespace profiler_gui {
EasyGlobals& EasyGlobals::instance()
{
static EasyGlobals globals;
return globals;
}
EasyGlobals::EasyGlobals()
: selected_thread(0U)
, selected_block(::profiler_gui::numeric_max<decltype(selected_block)>())
, selected_block_id(::profiler_gui::numeric_max<decltype(selected_block_id)>())
, begin_time(0)
, frame_time(4e4f)
, blocks_spacing(2)
, blocks_size_min(2)
, blocks_narrow_size(20)
, chrono_text_position(ChronoTextPosition_Center)
, time_units(TimeUnits_auto)
, connected(false)
, use_decorated_thread_name(true)
, enable_event_indicators(true)
, enable_statistics(true)
, enable_zero_length(true)
, add_zero_blocks_to_hierarchy(false)
, draw_graphics_items_borders(true)
, hide_narrow_children(false)
, hide_minsize_blocks(false)
, display_only_relevant_stats(true)
, collapse_items_on_tree_close(false)
, all_items_expanded_by_default(true)
, only_current_thread_hierarchy(false)
, highlight_blocks_with_same_id(true)
, selecting_block_changes_thread(true)
, bind_scene_and_tree_expand_status(true)
{
}
} // END of namespace profiler_gui.
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////

View File

@ -0,0 +1,199 @@
/************************************************************************
* file name : globals.h
* ----------------- :
* creation time : 2016/08/03
* author : Victor Zarubkin
* email : v.s.zarubkin@gmail.com
* ----------------- :
* description : The file contains declaration of global constants and variables for profiler gui.
* ----------------- :
* change log : * 2016/08/03 Victor Zarubkin: initial commit.
* :
* : *
* ----------------- :
* license : Lightweight profiler library for c++
* : Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
* :
* :
* : Licensed under the Apache License, Version 2.0 (the "License");
* : you may not use this file except in compliance with the License.
* : You may obtain a copy of the License at
* :
* : http://www.apache.org/licenses/LICENSE-2.0
* :
* : Unless required by applicable law or agreed to in writing, software
* : distributed under the License is distributed on an "AS IS" BASIS,
* : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* : See the License for the specific language governing permissions and
* : limitations under the License.
* :
* :
* : GNU General Public License Usage
* : Alternatively, this file may be used under the terms of the GNU
* : General Public License as published by the Free Software Foundation,
* : either version 3 of the License, or (at your option) any later version.
* :
* : This program is distributed in the hope that it will be useful,
* : but WITHOUT ANY WARRANTY; without even the implied warranty of
* : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
* : GNU General Public License for more details.
* :
* : You should have received a copy of the GNU General Public License
* : along with this program.If not, see <http://www.gnu.org/licenses/>.
************************************************************************/
#ifndef EASY_PROFILER__GUI_GLOBALS_H
#define EASY_PROFILER__GUI_GLOBALS_H
#include <string>
#include <QObject>
#include <QColor>
#include <QTextCodec>
#include <QSize>
#include "common_types.h"
#include "globals_qobjects.h"
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
namespace profiler_gui {
const QString ORGANAZATION_NAME = "EasyProfiler";
const QString APPLICATION_NAME = "Easy profiler gui application";
const QColor CHRONOMETER_COLOR = QColor::fromRgba(0x40000000 | (::profiler::colors::RichBlue & 0x00ffffff));// 0x402020c0);
const QColor CHRONOMETER_COLOR2 = QColor::fromRgba(0x40000000 | (::profiler::colors::Dark & 0x00ffffff));// 0x40408040);
const QRgb SELECTED_THREAD_BACKGROUND = 0x00e0e060;
const QRgb SELECTED_THREAD_FOREGROUND = 0x00ffffff - SELECTED_THREAD_BACKGROUND;
const qreal SCALING_COEFFICIENT = 1.25;
const qreal SCALING_COEFFICIENT_INV = 1.0 / SCALING_COEFFICIENT;
const QSize ICONS_SIZE(28, 28);
const uint16_t GRAPHICS_ROW_SIZE = 18;
const uint16_t GRAPHICS_ROW_SPACING = 2;
const uint16_t GRAPHICS_ROW_SIZE_FULL = GRAPHICS_ROW_SIZE + GRAPHICS_ROW_SPACING;
const uint16_t THREADS_ROW_SPACING = 8;
#ifdef _WIN32
const qreal FONT_METRICS_FACTOR = 1.05;
#else
const qreal FONT_METRICS_FACTOR = 1.;
#endif
//////////////////////////////////////////////////////////////////////////
template <class T>
inline auto toUnicode(const T& _inputString) -> decltype(QTextCodec::codecForLocale()->toUnicode(_inputString))
{
return QTextCodec::codecForLocale()->toUnicode(_inputString);
}
//////////////////////////////////////////////////////////////////////////
inline QString decoratedThreadName(bool _use_decorated_thread_name, const::profiler::BlocksTreeRoot& _root, const QString& _unicodeThreadWord)
{
if (_root.got_name())
{
QString rootname(toUnicode(_root.name()));
if (!_use_decorated_thread_name || rootname.contains(_unicodeThreadWord, Qt::CaseInsensitive))
return QString("%1 %2").arg(rootname).arg(_root.thread_id);
return QString("%1 Thread %2").arg(rootname).arg(_root.thread_id);
}
return QString("Thread %1").arg(_root.thread_id);
}
inline QString decoratedThreadName(bool _use_decorated_thread_name, const ::profiler::BlocksTreeRoot& _root)
{
if (_root.got_name())
{
QString rootname(toUnicode(_root.name()));
if (!_use_decorated_thread_name || rootname.contains(toUnicode("thread"), Qt::CaseInsensitive))
return QString("%1 %2").arg(rootname).arg(_root.thread_id);
return QString("%1 Thread %2").arg(rootname).arg(_root.thread_id);
}
return QString("Thread %1").arg(_root.thread_id);
}
//////////////////////////////////////////////////////////////////////////
enum ChronometerTextPosition : int8_t
{
ChronoTextPosition_Center = 0,
ChronoTextPosition_Top,
ChronoTextPosition_Bottom,
}; // END of enum ChronometerTextPosition.
//////////////////////////////////////////////////////////////////////////
struct EasyGlobals Q_DECL_FINAL
{
static EasyGlobals& instance();
EasyGlobalSignals events; ///< Global signals
::profiler::thread_blocks_tree_t profiler_blocks; ///< Profiler blocks tree loaded from file
::profiler::descriptors_list_t descriptors; ///< Profiler block descriptors list
EasyBlocks gui_blocks; ///< Profiler graphics blocks builded by GUI
::profiler::timestamp_t begin_time; ///<
::profiler::thread_id_t selected_thread; ///< Current selected thread id
::profiler::block_index_t selected_block; ///< Current selected profiler block index
::profiler::block_id_t selected_block_id; ///< Current selected profiler block id
float frame_time; ///< Value in microseconds to be displayed at minimap on graphics scrollbar
int blocks_spacing; ///< Minimum blocks spacing on diagram
int blocks_size_min; ///< Minimum blocks size on diagram
int blocks_narrow_size; ///< Width indicating narrow blocks
ChronometerTextPosition chrono_text_position; ///< Selected interval text position
TimeUnits time_units; ///< Units type for time (milliseconds, microseconds, nanoseconds or auto-definition)
bool connected; ///< Is connected to source (to be able to capture profiling information)
bool use_decorated_thread_name; ///< Add "Thread" to the name of each thread (if there is no one)
bool enable_event_indicators; ///< Enable event indicators painting (These are narrow rectangles at the bottom of each thread)
bool enable_statistics; ///< Enable gathering and using statistics (Disable if you want to consume less memory)
bool enable_zero_length; ///< Enable zero length blocks (if true, then such blocks will have width == 1 pixel on each scale)
bool add_zero_blocks_to_hierarchy; ///< Enable adding zero blocks into hierarchy tree
bool draw_graphics_items_borders; ///< Draw borders for graphics blocks or not
bool hide_narrow_children; ///< Hide children for narrow graphics blocks (See blocks_narrow_size)
bool hide_minsize_blocks; ///< Hide blocks which screen size is less than blocks_size_min
bool display_only_relevant_stats; ///< Display only relevant information in ProfTreeWidget (excludes min, max, average times if there are only 1 calls number)
bool collapse_items_on_tree_close; ///< Collapse all items which were displayed in the hierarchy tree after tree close/reset
bool all_items_expanded_by_default; ///< Expand all items after file is opened
bool only_current_thread_hierarchy; ///< Build hierarchy tree for current thread only
bool highlight_blocks_with_same_id; ///< Highlight all blocks with same id on diagram
bool selecting_block_changes_thread; ///< If true then current selected thread will change every time you select block
bool bind_scene_and_tree_expand_status; /** \brief If true then items on graphics scene and in the tree (blocks hierarchy) are binded on each other
so expanding/collapsing items on scene also expands/collapse items in the tree. */
private:
EasyGlobals();
}; // END of struct EasyGlobals.
//////////////////////////////////////////////////////////////////////////
} // END of namespace profiler_gui.
#ifndef IGNORE_GLOBALS_DECLARATION
static ::profiler_gui::EasyGlobals& EASY_GLOBALS = ::profiler_gui::EasyGlobals::instance();
inline ::profiler_gui::EasyBlock& easyBlock(::profiler::block_index_t i) {
return EASY_GLOBALS.gui_blocks[i];
}
inline ::profiler::SerializedBlockDescriptor& easyDescriptor(::profiler::block_id_t i) {
return *EASY_GLOBALS.descriptors[i];
}
inline ::profiler::BlocksTree& blocksTree(::profiler::block_index_t i) {
return easyBlock(i).tree;
}
#endif
#define SET_ICON(objectName, iconName) { QIcon icon(iconName); if (!icon.isNull()) objectName->setIcon(icon); }
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
#endif // EASY_PROFILER__GUI_GLOBALS_H

View File

@ -0,0 +1,62 @@
/************************************************************************
* file name : globals_qobjects.cpp
* ----------------- :
* creation time : 2016/08/08
* authors : Victor Zarubkin, Sergey Yagovtsev
* email : v.s.zarubkin@gmail.com, yse.sey@gmail.com
* ----------------- :
* description : The file contains implementation of EasyGlobalSignals QObject class.
* ----------------- :
* change log : * 2016/08/08 Sergey Yagovtsev: moved sources from globals.cpp
* :
* : *
* ----------------- :
* license : Lightweight profiler library for c++
* : Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
* :
* :
* : Licensed under the Apache License, Version 2.0 (the "License");
* : you may not use this file except in compliance with the License.
* : You may obtain a copy of the License at
* :
* : http://www.apache.org/licenses/LICENSE-2.0
* :
* : Unless required by applicable law or agreed to in writing, software
* : distributed under the License is distributed on an "AS IS" BASIS,
* : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* : See the License for the specific language governing permissions and
* : limitations under the License.
* :
* :
* : GNU General Public License Usage
* : Alternatively, this file may be used under the terms of the GNU
* : General Public License as published by the Free Software Foundation,
* : either version 3 of the License, or (at your option) any later version.
* :
* : This program is distributed in the hope that it will be useful,
* : but WITHOUT ANY WARRANTY; without even the implied warranty of
* : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
* : GNU General Public License for more details.
* :
* : You should have received a copy of the GNU General Public License
* : along with this program.If not, see <http://www.gnu.org/licenses/>.
************************************************************************/
#include "globals_qobjects.h"
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
namespace profiler_gui {
EasyGlobalSignals::EasyGlobalSignals() : QObject()
{
}
EasyGlobalSignals::~EasyGlobalSignals()
{
}
} // END of namespace profiler_gui.
//////////////////////////////////////////////////////////////////////////

View File

@ -0,0 +1,67 @@
/************************************************************************
* file name : globals_qobjects.h
* ----------------- :
* creation time : 2016/08/08
* authors : Victor Zarubkin, Sergey Yagovtsev
* email : v.s.zarubkin@gmail.com, yse.sey@gmail.com
* ----------------- :
* description : The file contains declaration of EasyGlobalSignals QObject class.
* ----------------- :
* change log : * 2016/08/08 Sergey Yagovtsev: moved sources from globals.h
* :
* : *
* ----------------- :
* license : Lightweight profiler library for c++
* : Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
* :
* : This program is free software : you can redistribute it and / or modify
* : it under the terms of the GNU General Public License as published by
* : the Free Software Foundation, either version 3 of the License, or
* : (at your option) any later version.
* :
* : This program is distributed in the hope that it will be useful,
* : but WITHOUT ANY WARRANTY; without even the implied warranty of
* : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
* : GNU General Public License for more details.
* :
* : You should have received a copy of the GNU General Public License
* : along with this program.If not, see <http://www.gnu.org/licenses/>.
************************************************************************/
#ifndef EASY__GLOBALS_QOBJECTS_H___
#define EASY__GLOBALS_QOBJECTS_H___
#include <QObject>
#include "easy/profiler.h"
namespace profiler_gui {
class EasyGlobalSignals Q_DECL_FINAL : public QObject
{
Q_OBJECT
public:
EasyGlobalSignals();
virtual ~EasyGlobalSignals();
signals:
void selectedThreadChanged(::profiler::thread_id_t _id);
void selectedBlockChanged(uint32_t _block_index);
void selectedBlockIdChanged(::profiler::block_id_t _id);
void itemsExpandStateChanged();
void blockStatusChanged(::profiler::block_id_t _id, ::profiler::EasyBlockStatus _status);
void connectionChanged(bool _connected);
void blocksRefreshRequired(bool);
void timelineMarkerChanged();
void hierarchyFlagChanged(bool);
void threadNameDecorationChanged();
void refreshRequired();
void blocksTreeModeChanged();
}; // END of class EasyGlobalSignals.
} // END of namespace profiler_gui.
#endif // EASY__GLOBALS_QOBJECTS_H___

View File

@ -0,0 +1,24 @@
logo.svg - Icon made by Freepik from www.flaticon.com
off.svg - Icon made by Freepik from www.flaticon.com
open-folder.svg - Icon made by Freepik from www.flaticon.com
open-folder2.svg - Icon made by Freepik from www.flaticon.com
reload-folder2.svg - Icon made by Freepik from www.flaticon.com
reload.svg - Icon made by Freepik from www.flaticon.com
expand.svg - Icon made by Freepik from www.flaticon.com
collapse.svg - Icon made by Freepik from www.flaticon.com
colors.svg - Icon made by Freepik from www.flaticon.com
colors-black.svg - Icon made by Freepik from www.flaticon.com
save.svg - Icon made by Freepik from www.flaticon.com
statistics.svg - Icon made by Freepik from www.flaticon.com
statistics2.svg - Icon made by Freepik from www.flaticon.com
lan.svg - Icon made by Freepik from www.flaticon.com
lan_on.svg - Icon made by Freepik from www.flaticon.com
wifi.svg - Icon made by Freepik from www.flaticon.com
wifi_on.svg - Icon made by Freepik from www.flaticon.com
play.svg - Icon made by Google from www.flaticon.com
stop.svg - Icon made by Google from www.flaticon.com
delete.svg - Icon made by Freepik from www.flaticon.com
list.svg - Icon made by Freepik from www.flaticon.com
search-prev.svg - Icon made by Freepik from www.flaticon.com
search-next.svg - Icon made by Freepik from www.flaticon.com
settings.svg - Icon made by Freepik from www.flaticon.com

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 18.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 210.002 210.002" style="enable-background:new 0 0 210.002 210.002;" xml:space="preserve">
<g>
<path fill="#484848" d="M195.765,76.815l-77.424,11.118l11.119-77.422l19.932,19.931l30.445-30.441l26.439,26.44
l-30.441,30.444L195.765,76.815z"/>
<path fill="#484848" d="M34.168,153.117L3.725,183.563l26.439,26.439l30.445-30.441l19.932,19.93l11.119-77.422
l-77.422,11.119L34.168,153.117z"/>
<path fill="#f44336" d="M60.61,30.441L30.164,0L3.725,26.44l30.443,30.444l-19.93,19.931L91.66,87.933L80.541,10.511
L60.61,30.441z"/>
<path fill="#f44336" d="M195.765,133.188l-77.424-11.119l11.119,77.422l19.932-19.93l30.445,30.441l26.439-26.439l-30.441-30.445
L195.765,133.188z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 17.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 441.902 441.902" style="enable-background:new 0 0 441.902 441.902;" xml:space="preserve">
<g>
<path fill="#484848" d="M372.231,170.869c-4.097-2.365-8.303-4.509-12.595-6.438c0.471-4.651,0.713-9.369,0.713-14.143
c0-76.864-62.534-139.397-139.397-139.397S81.553,73.425,81.553,150.289c0,4.773,0.242,9.492,0.713,14.143
c-4.293,1.929-8.499,4.073-12.595,6.438C3.105,209.302-19.783,294.724,18.648,361.29c24.829,43.005,71.133,69.721,120.843,69.721
c24.332,0,48.392-6.466,69.578-18.698c4.114-2.375,8.076-4.939,11.882-7.675c3.806,2.736,7.768,5.3,11.882,7.675
c21.187,12.232,45.246,18.698,69.578,18.698c49.709,0,96.014-26.715,120.843-69.721
C461.685,294.724,438.797,209.302,372.231,170.869z M101.553,150.289c0-65.836,53.562-119.397,119.397-119.397
s119.397,53.562,119.397,119.397c0,2.377-0.078,4.735-0.216,7.078c-12.175-3.419-24.788-5.194-37.48-5.194
c-29.746,0-58.267,9.573-81.702,26.471c-23.435-16.898-51.956-26.471-81.702-26.471c-12.692,0-25.306,1.775-37.48,5.194
C101.631,155.024,101.553,152.665,101.553,150.289z M254.699,322.493c-5.869,21.903-17.558,41.245-33.749,56.329
c-16.191-15.084-27.88-34.426-33.749-56.329c-3.367-12.566-4.654-25.361-3.917-37.981c11.986,3.368,24.618,5.174,37.666,5.174
s25.68-1.807,37.666-5.174C259.353,297.133,258.066,309.927,254.699,322.493z M220.951,269.687c-12.088,0-23.76-1.812-34.765-5.168
c2.646-11.307,6.974-22.286,12.945-32.627c5.947-10.3,13.335-19.508,21.82-27.431c8.486,7.923,15.873,17.13,21.82,27.431
c5.97,10.34,10.298,21.32,12.945,32.627C244.711,267.875,233.039,269.687,220.951,269.687z M167.433,256.999
c-31.244-15.733-54.677-44.784-62.787-79.655c11.197-3.412,22.864-5.173,34.603-5.173c23.75,0,46.588,7.124,65.837,19.809
c-8.984,8.764-16.853,18.787-23.276,29.911C175.367,233.053,170.564,244.851,167.433,256.999z M260.092,221.892
c-6.423-11.124-14.292-21.147-23.276-29.911c19.249-12.685,42.087-19.809,65.837-19.809c11.738,0,23.405,1.761,34.603,5.173
c-8.109,34.87-31.543,63.921-62.787,79.655C271.338,244.851,266.535,233.053,260.092,221.892z M199.069,394.992
c-18.15,10.479-38.752,16.018-59.578,16.018c-42.587,0-82.254-22.884-103.522-59.721c-32.917-57.015-13.313-130.182,43.703-163.1
c2.042-1.179,4.12-2.286,6.221-3.34c10.581,41.328,39.68,75.319,77.896,92.57c-1.692,16.636-0.362,33.614,4.096,50.25
c6.578,24.55,19.418,46.345,37.159,63.631C203.094,392.581,201.106,393.817,199.069,394.992z M405.933,351.29
c-21.268,36.837-60.936,59.721-103.522,59.721c-20.826,0-41.428-5.539-59.578-16.018c-2.036-1.176-4.024-2.411-5.974-3.691
c17.741-17.286,30.581-39.081,37.159-63.631c4.458-16.636,5.788-33.614,4.096-50.25c38.216-17.251,67.315-51.242,77.896-92.57
c2.101,1.053,4.179,2.16,6.221,3.34C419.246,221.108,438.851,294.275,405.933,351.29z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 297 297" style="enable-background:new 0 0 297 297;" xml:space="preserve">
<g>
<path fill="#484848" d="M233.51,115.94c36.58,10.3,63.49,43.94,63.49,83.78c0,47.99-39.04,87.04-87.04,87.04c-23.97,0-45.7-9.74-61.46-25.47
c-15.75,15.73-37.49,25.47-61.46,25.47C39.05,286.76,0,247.71,0,199.72c0-39.84,26.91-73.48,63.5-83.78
c-1.32-6.01-2.04-12.25-2.04-18.66c0-47.99,39.05-87.04,87.04-87.04c48,0,87.04,39.05,87.04,87.04
C235.54,103.69,234.83,109.93,233.51,115.94z M286.82,199.72c0-35.18-23.77-64.89-56.08-73.98c-9.28,26.75-31.26,47.6-58.69,55.32
c1.32,6.01,2.03,12.25,2.03,18.66c0,20.36-7.04,39.09-18.8,53.93c13.94,14.14,33.3,22.92,54.68,22.92
C252.34,276.57,286.82,242.1,286.82,199.72z M223.56,113.75c1.17-5.31,1.8-10.81,1.8-16.47c0-42.38-34.48-76.85-76.86-76.85
S71.65,54.9,71.65,97.28c0,5.66,0.63,11.16,1.79,16.47c4.44-0.7,8.98-1.07,13.6-1.07c23.97,0,45.71,9.74,61.46,25.47
c15.76-15.73,37.49-25.47,61.46-25.47C214.59,112.68,219.13,113.05,223.56,113.75z M220.71,123.63c-3.52-0.5-7.1-0.77-10.75-0.77
c-21.38,0-40.74,8.78-54.68,22.92c6,7.58,10.77,16.17,14,25.48C193.1,164.56,212.27,146.67,220.71,123.63z M163.9,199.72
c0-5.66-0.63-11.16-1.8-16.47c-4.43,0.7-8.97,1.07-13.6,1.07c-4.62,0-9.16-0.37-13.6-1.07c-1.16,5.31-1.79,10.81-1.79,16.47
c0,17.27,5.73,33.24,15.39,46.09C158.16,232.96,163.9,216.99,163.9,199.72z M159.24,173.37c-2.61-7.13-6.25-13.77-10.74-19.74
c-4.49,5.97-8.13,12.61-10.74,19.74c3.51,0.5,7.1,0.77,10.74,0.77C152.15,174.14,155.73,173.87,159.24,173.37z M127.73,171.26
c3.23-9.31,7.99-17.9,14-25.48c-13.95-14.14-33.31-22.92-54.69-22.92c-3.64,0-7.23,0.27-10.74,0.77
C84.73,146.67,103.91,164.56,127.73,171.26z M141.73,253.65c-11.76-14.84-18.81-33.57-18.81-53.93c0-6.41,0.72-12.65,2.04-18.66
c-27.44-7.72-49.41-28.57-58.69-55.32c-32.32,9.09-56.08,38.8-56.08,73.98c0,42.38,34.47,76.85,76.85,76.85
C108.42,276.57,127.78,267.79,141.73,253.65z"/>
<path fill="#3498DB" d="M230.74,125.74c32.31,9.09,56.08,38.8,56.08,73.98c0,42.38-34.48,76.85-76.86,76.85
c-21.38,0-40.74-8.78-54.68-22.92c11.76-14.84,18.8-33.57,18.8-53.93c0-6.41-0.71-12.65-2.03-18.66
C199.48,173.34,221.46,152.49,230.74,125.74z"/>
<path fill="#D35400" d="M225.36,97.28c0,5.66-0.63,11.16-1.8,16.47c-4.43-0.7-8.97-1.07-13.6-1.07
c-23.97,0-45.7,9.74-61.46,25.47c-15.75-15.73-37.49-25.47-61.46-25.47c-4.62,0-9.16,0.37-13.6,1.07
c-1.16-5.31-1.79-10.81-1.79-16.47c0-42.38,34.47-76.85,76.85-76.85S225.36,54.9,225.36,97.28z"/>
<path fill="#5E345E" d="M209.96,122.86c3.65,0,7.23,0.27,10.75,0.77c-8.44,23.04-27.61,40.93-51.43,47.63
c-3.23-9.31-8-17.9-14-25.48C169.22,131.64,188.58,122.86,209.96,122.86z"/>
<path fill="#1ABC9C" d="M162.1,183.25c1.17,5.31,1.8,10.81,1.8,16.47c0,17.27-5.74,33.24-15.4,46.09
c-9.66-12.85-15.39-28.82-15.39-46.09c0-5.66,0.63-11.16,1.79-16.47c4.44,0.7,8.98,1.07,13.6,1.07
C153.13,184.32,157.67,183.95,162.1,183.25z"/>
<path fill="#503B2C" d="M148.5,153.63c4.49,5.97,8.13,12.61,10.74,19.74c-3.51,0.5-7.09,0.77-10.74,0.77
c-3.64,0-7.23-0.27-10.74-0.77C140.37,166.24,144.01,159.6,148.5,153.63z"/>
<path fill="#FFA800" d="M141.73,145.78c-6.01,7.58-10.77,16.17-14,25.48c-23.82-6.7-43-24.59-51.43-47.63
c3.51-0.5,7.1-0.77,10.74-0.77C108.42,122.86,127.78,131.64,141.73,145.78z"/>
<path fill="#FFCD02" d="M122.92,199.72c0,20.36,7.05,39.09,18.81,53.93c-13.95,14.14-33.31,22.92-54.69,22.92
c-42.38,0-76.85-34.47-76.85-76.85c0-35.18,23.76-64.89,56.08-73.98c9.28,26.75,31.25,47.6,58.69,55.32
C123.64,187.07,122.92,193.31,122.92,199.72z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 443 443" style="enable-background:new 0 0 443 443;" xml:space="preserve">
<g>
<rect fill="#484848" x="61.785" y="128" width="60" height="290"/>
<path fill="#484848" d="M211.785,250.65V128h-60v290h44.172c-14.861-21.067-23.602-46.746-23.602-74.43
C172.356,307.145,187.486,274.193,211.785,250.65z"/>
<path fill="#484848" d="M301.785,214.141l0-86.141h-60v100.918C259.731,219.488,280.144,214.141,301.785,214.141z"/>
<path fill="#484848" d="M321.785,38h-83.384V0H125.169v38H41.785v60h280V38z M155.169,30h53.232v8h-53.232V30z"/>
<path fill="#f44336" d="M301.785,244.141c-54.826,0-99.429,44.604-99.429,99.429S246.959,443,301.785,443s99.43-44.604,99.43-99.43
S356.611,244.141,301.785,244.141z M355.961,376.533l-21.213,21.213l-32.963-32.963l-32.963,32.963l-21.213-21.213l32.963-32.963
l-32.963-32.963l21.213-21.213l32.963,32.963l32.963-32.963l21.213,21.213l-32.963,32.963L355.961,376.533z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 18.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 210 210" style="enable-background:new 0 0 210 210;" xml:space="preserve">
<g>
<path fill="#f44336" d="M34.774,152.509l26.441,26.442l19.93,19.931L3.724,210l11.119-77.422L34.774,152.509z"/>
<path fill="#484848" d="M175.226,152.509l-30.445-30.441l-26.44,26.439l30.441,30.444l-19.93,19.931L206.276,210l-11.119-77.422L175.226,152.509z"/>
<path fill="#f44336" d="M65.22,122.067l26.439,26.439l-30.443,30.444l-26.441-26.442L65.22,122.067z"/>
<path fill="#484848" d="M61.216,31.049l30.443,30.444L65.22,87.933
L34.774,57.491L14.843,77.422L3.724,0l77.422,11.118L61.216,31.049z"/>
<path fill="#f44336" d="M118.341,61.493l30.441-30.444l-19.93-19.931L206.276,0
l-11.119,77.422l-19.932-19.931L144.78,87.933L118.341,61.493z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 94.414 94.414" style="enable-background:new 0 0 94.414 94.414;" xml:space="preserve">
<g>
<path fill="#484848" d="M86.522,60.468v-3.16V38.34V19.372c0-1.736-1.421-3.16-3.164-3.16H36.25v2.827h43.068
c1.514,0,2.759,1.242,2.759,2.759v33.069c0,1.525-1.245,2.759-2.759,2.759H24.179c-0.229,0-0.433-0.075-0.648-0.132v17.196h66.144
c2.616,0,4.738-2.126,4.738-4.746L86.522,60.468z M58.07,73.112H45.426c-0.437,0-0.791-0.351-0.791-0.791
c0-0.44,0.354-0.791,0.791-0.791H58.07c0.44,0,0.791,0.351,0.791,0.791C58.861,72.762,58.511,73.112,58.07,73.112z M38.716,69.952
l2.412-2.895h21.237l2.416,2.895H38.716z"/>
<g>
<g>
<path fill="#484848" d="M31.92,42.935H0V14.258c0-1.793,1.453-3.246,3.246-3.246c1.793,0,3.246,1.453,3.246,3.246v22.178
h18.936V14.258c0-1.793,1.453-3.246,3.246-3.246c1.789,0,3.246,1.453,3.246,3.246C31.92,14.258,31.92,42.935,31.92,42.935z"/>
</g>
<g>
<path fill="#f44336" d="M12.712,31.784V14.262c0-1.793,1.453-3.246,3.246-3.246s3.246,1.453,3.246,3.246v17.522H12.712z"/>
</g>
<g>
<path fill="#f44336" d="M15.962,83.402c-1.793,0-3.246-1.446-3.246-3.242V47.595h6.492v32.564
C19.208,81.949,17.755,83.402,15.962,83.402z"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 94.414 94.414" style="enable-background:new 0 0 94.414 94.414;" xml:space="preserve">
<g>
<path fill="#484848" d="M86.522,60.468v-3.16V38.34V19.372c0-1.736-1.421-3.16-3.164-3.16H36.25v2.827h43.068
c1.514,0,2.759,1.242,2.759,2.759v33.069c0,1.525-1.245,2.759-2.759,2.759H24.179c-0.229,0-0.433-0.075-0.648-0.132v17.196h66.144
c2.616,0,4.738-2.126,4.738-4.746L86.522,60.468z M58.07,73.112H45.426c-0.437,0-0.791-0.351-0.791-0.791
c0-0.44,0.354-0.791,0.791-0.791H58.07c0.44,0,0.791,0.351,0.791,0.791C58.861,72.762,58.511,73.112,58.07,73.112z M38.716,69.952
l2.412-2.895h21.237l2.416,2.895H38.716z"/>
<g>
<g>
<path fill="#484848" d="M31.92,42.935H0V14.258c0-1.793,1.453-3.246,3.246-3.246c1.793,0,3.246,1.453,3.246,3.246v22.178
h18.936V14.258c0-1.793,1.453-3.246,3.246-3.246c1.789,0,3.246,1.453,3.246,3.246C31.92,14.258,31.92,42.935,31.92,42.935z"/>
</g>
<g>
<path fill="#4caf50" d="M12.712,31.784V14.262c0-1.793,1.453-3.246,3.246-3.246s3.246,1.453,3.246,3.246v17.522H12.712z"/>
</g>
<g>
<path fill="#4caf50" d="M15.962,83.402c-1.793,0-3.246-1.446-3.246-3.242V47.595h6.492v32.564
C19.208,81.949,17.755,83.402,15.962,83.402z"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 485.69 485.69" style="enable-background:new 0 0 485.69 485.69;" xml:space="preserve">
<g>
<path fill="#484848" d="M410.428,34.738h-76.405l5.155,23.852c0.634,2.961,0.603,5.934,0.271,8.859h54.621V452.98H91.588V67.449h54.637
c-0.332-2.941-0.348-5.914,0.285-8.891l5.156-23.82H75.248c-9.031,0-16.34,7.324-16.34,16.354v418.243
c0,9.016,7.309,16.354,16.34,16.354h335.18c9.031,0,16.354-7.341,16.354-16.354V51.093
C426.783,42.062,419.459,34.738,410.428,34.738z"/>
<path fill="#484848" d="M355.568,152.949h-111.71c-9.047,0-16.355,7.324-16.355,16.34c0,9.035,7.309,16.355,16.355,16.355h111.71
c9.047,0,16.354-7.32,16.354-16.355C371.924,160.273,364.615,152.949,355.568,152.949z"/>
<path fill="#484848" d="M355.568,253.254h-111.71c-9.047,0-16.355,7.323-16.355,16.354c0,9.021,7.309,16.357,16.355,16.357h111.71
c9.047,0,16.354-7.34,16.354-16.357C371.924,260.577,364.615,253.254,355.568,253.254z"/>
<path fill="#f44336" d="M119.556,156.792c-6.898,5.82-7.786,16.137-1.965,23.047l23.855,28.27c3.117,3.699,7.688,5.805,12.496,5.805
c0.398,0,0.792-0.016,1.203-0.047c5.219-0.379,9.949-3.258,12.703-7.719l42.914-69.477c4.746-7.688,2.375-17.75-5.312-22.492
c-7.688-4.777-17.75-2.375-22.497,5.313l-31.066,50.273l-9.301-11.012C136.763,151.843,126.467,150.956,119.556,156.792z"/>
<path fill="#484848" d="M158.72,245.094c-13.554,0-24.535,10.978-24.535,24.517c0,13.543,10.98,24.52,24.535,24.52
c13.543,0,24.52-10.977,24.52-24.52C183.24,256.07,172.263,245.094,158.72,245.094z"/>
<path fill="#484848" d="M355.568,351.359h-111.71c-9.047,0-16.355,7.309-16.355,16.358c0,9.017,7.309,16.34,16.355,16.34h111.71
c9.047,0,16.354-7.323,16.354-16.34C371.924,358.667,364.615,351.359,355.568,351.359z"/>
<path fill="#484848" d="M158.72,343.199c-13.554,0-24.535,10.977-24.535,24.52c0,13.539,10.98,24.521,24.535,24.521
c13.543,0,24.52-10.979,24.52-24.521C183.24,354.176,172.263,343.199,158.72,343.199z"/>
<path fill="#484848" d="M173.463,75.613h138.73c3.401,0,6.613-1.521,8.746-4.176c2.137-2.629,2.961-6.105,2.229-9.43L311.686,8.859
C310.564,3.687,305.994,0,300.708,0H184.963c-5.281,0-9.852,3.688-10.977,8.859l-11.5,53.148
c-0.695,3.324,0.125,6.801,2.247,9.43C166.868,74.093,170.08,75.613,173.463,75.613z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 175 KiB

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 705.299 705.299" style="enable-background:new 0 0 705.299 705.299;" xml:space="preserve">
<g>
<path fill="#484848" d="M395.233,117.99V91.598l64.906,0.023v-5.55C460.151,38.549,421.636,0,374.08,0h-62.632
c-47.511,0-86.06,38.549-86.06,86.071v5.515l66.343,0.023v26.163C152.565,141.993,46.651,263.051,46.651,409.157
c0,163.594,132.571,296.142,296.107,296.142c163.537,0,296.107-132.548,296.107-296.142
C638.876,263.557,533.698,142.786,395.233,117.99z M342.758,637.52c-125.907,0-228.339-102.433-228.339-228.362
c0-125.896,102.433-228.305,228.339-228.305c125.895,0,228.339,102.41,228.339,228.305
C571.097,535.087,468.665,637.52,342.758,637.52z"/>
<path fill="#f44336" d="M651.987,153.333l-48.017-48.028c-4.274-4.286-10.065-6.688-16.098-6.688s-11.823,2.401-16.097,6.665l-38.929,38.939
l80.246,80.2l38.894-38.917C660.869,176.612,660.869,162.227,651.987,153.333z"/>
<path fill="#f44336" d="M341.724,195.237c-117.714,0.54-212.966,96.125-212.966,213.92c0,118.231,95.815,214.022,214.012,214.022
c118.185,0,213.989-95.769,214-214H341.724V195.237z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 26.009 26.009" style="enable-background:new 0 0 26.009 26.009;" xml:space="preserve">
<g>
<path fill="#484848" d="M17.284,2.033v3.3c3.006,1.551,5.065,4.683,5.065,8.299c0,5.161-4.184,9.344-9.343,9.344c-5.16,0-9.346-4.183-9.346-9.344
c0-3.316,1.735-6.223,4.34-7.881V2.32C3.662,4.242,0.63,8.581,0.63,13.632c0,6.834,5.539,12.377,12.374,12.377
c6.834,0,12.374-5.543,12.374-12.377C25.378,8.304,22.003,3.779,17.284,2.033z"/>
<path fill="#f44336" d="M12.766,15.229c1.359,0,2.457-0.803,2.457-1.79V1.795C15.224,0.804,14.125,0,12.766,0c-1.357,0-2.456,0.804-2.456,1.795
V13.44C10.311,14.427,11.41,15.229,12.766,15.229z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 933 B

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 17.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 250.604 250.604" style="enable-background:new 0 0 250.604 250.604;" xml:space="preserve">
<g>
<path fill="#484848" d="M66.34,115.302h173.065c4.148,0,6.846,2.708,8.084,4.322c2.898,3.776,3.847,8.949,2.537,13.839l-23.92,89.297
c-1.528,5.707-5.796,9.542-10.619,9.542H42.422c-4.148,0-6.846-2.708-8.084-4.322c-2.898-3.776-3.847-8.949-2.537-13.839
l23.919-89.297C57.249,119.137,61.517,115.302,66.34,115.302z"/>
<path fill="#f44336" d="M17.312,210.26l23.919-89.297
c3.31-12.358,13.399-20.661,25.108-20.661H229v-42c0-4.143-2.524-7-6.667-7H130v-2.633c0-17.021-13.014-30.367-30.033-30.367H31.2
C14.18,18.302,0,31.649,0,48.669v9.633v33v115.5c0,4.143,3.69,7.5,7.833,7.5h8.684C16.697,212.947,16.954,211.597,17.312,210.26z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 17.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 247.355 247.355" style="enable-background:new 0 0 247.355 247.355;" xml:space="preserve">
<g>
<path fill="#484848" d="M181.751,79.678h64.049c0.617,0,0.995,0.275,1.204,0.506c0.27,0.297,0.385,0.66,0.344,1.078l-14.7,147.766
c-0.086,0.863-0.824,1.65-1.548,1.65H15.792c-0.748,0-1.44-0.667-1.543-1.486L0.013,115.176c-0.05-0.396,0.041-0.719,0.278-0.986
c0.168-0.191,0.557-0.512,1.265-0.512h151.291c6.107,0,11.713-3.423,14.639-8.948l12.891-24.474
C180.653,79.734,181.429,79.678,181.751,79.678z"/>
<path fill="#f44336" d="M152.847,98.678c0.513,0,1.077-0.392,1.375-0.953l12.891-24.474
c2.803-5.294,8.409-8.573,14.638-8.573h54.594v-16.75c0-8.837-5.87-15.25-14.417-15.25H91.428c-0.536-0.009-1.569-0.809-1.752-1.342
c-0.001-0.113-0.005-0.227-0.011-0.338c-0.304-8.467-6.278-14.32-14.738-14.32h-48.5c-9.393,0-17.083,6.479-17.083,14.75v67.25
H152.847z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 510 510" style="enable-background:new 0 0 510 510;" xml:space="preserve">
<g>
<path fill="#f44336" d="M204,369.75L357,255L204,140.25V369.75z"/>
<path fill="#484848" d="M255,0C114.75,0,0,114.75,0,255s114.75,255,255,255s255-114.75,255-255
S395.25,0,255,0z M255,459c-112.2,0-204-91.8-204-204S142.8,51,255,51s204,91.8,204,204S367.2,459,255,459z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 750 B

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 17.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 247.355 247.355" style="enable-background:new 0 0 247.355 247.355;" xml:space="preserve">
<g>
<path fill="#f44336" d="M9.344,98.678v-67.25c0-8.271,7.69-14.75,17.083-14.75h48.5c8.46,0,14.435,5.854,14.738,14.32
c0.006,0.111,0.01,0.225,0.011,0.338c0.183,0.533,1.216,1.333,1.752,1.342h130.499c8.547,0,14.417,6.413,14.417,15.25v16.75h-54.594
c-6.229,0-11.835,3.279-14.638,8.573l-12.891,24.474c-0.298,0.562-0.862,0.953-1.375,0.953H9.344z"/>
<path fill="#484848" d="M247.347,81.262l-14.7,147.766
c-0.086,0.863-0.824,1.65-1.548,1.65H15.792c-0.748,0-1.44-0.667-1.543-1.486L0.013,115.176c-0.05-0.396,0.041-0.719,0.278-0.986
c0.168-0.191,0.557-0.512,1.265-0.512h151.291c6.107,0,11.713-3.423,14.639-8.948l12.891-24.474
c0.276-0.521,1.053-0.578,1.374-0.578h64.049c0.617,0,0.995,0.275,1.204,0.506C247.273,80.48,247.388,80.844,247.347,81.262z"/>
<path fill="#f44336" d="M203.177,188.998c0-4.143-3.357-7.5-7.5-7.5s-7.5,3.357-7.5,7.5c0,8.336-6.781,15.117-15.116,15.117
c-4.563,0-8.651-2.041-11.425-5.247c2.581,0.161,5.176-1.011,6.714-3.319c2.298-3.446,1.366-8.103-2.08-10.4l-11.466-7.645
c-2.52-1.68-5.801-1.68-8.32,0l-11.467,7.645c-3.446,2.298-4.378,6.954-2.08,10.4c1.445,2.168,3.823,3.341,6.247,3.341
c1.43,0,2.875-0.408,4.153-1.261l0.734-0.489c3.561,12.662,15.205,21.976,28.99,21.976
C189.667,219.115,203.177,205.604,203.177,188.998z M212.917,154.81c-2.298-3.446-6.954-4.377-10.4-2.08l-0.733,0.489
c-3.562-12.662-15.205-21.975-28.99-21.975c-16.606,0-30.117,13.511-30.117,30.117c0,4.143,3.357,7.5,7.5,7.5s7.5-3.357,7.5-7.5
c0-8.336,6.781-15.117,15.117-15.117c4.563,0,8.651,2.041,11.425,5.248c-2.582-0.161-5.177,1.012-6.715,3.319
c-2.298,3.446-1.366,8.103,2.08,10.4l11.467,7.645c1.26,0.84,2.71,1.26,4.16,1.26s2.9-0.42,4.16-1.26l11.466-7.645
C214.284,162.913,215.215,158.257,212.917,154.81z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 502.707 502.707" style="enable-background:new 0 0 502.707 502.707;" xml:space="preserve">
<g>
<path fill="#484848" d="M203.758,153.541l37.576,73.686L297.03,55.674L125.456,0.022l37.274,73.125
C75.002,104.467,12.166,188.054,12.166,286.525c0,101.383,66.546,187.17,158.351,216.161
c-55.307-34.902-92.15-96.378-92.15-166.526C78.345,252.788,130.525,182.208,203.758,153.541z"/>
<path fill="#f44336" d="M298.993,349.209l-37.598-73.707l-55.631,171.531l171.509,55.674l-37.296-73.147
c87.75-31.278,150.564-114.886,150.564-213.4C490.541,114.8,424.017,29.013,332.212,0c55.286,34.902,92.172,96.357,92.172,166.526
C424.405,249.941,372.225,320.477,298.993,349.209z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 983 B

View File

@ -0,0 +1,73 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
id="Layer_1"
x="0px"
y="0px"
viewBox="0 0 512 512"
style="enable-background:new 0 0 512 512;"
xml:space="preserve"
inkscape:version="0.91 r13725"
sodipodi:docname="save.svg"><metadata
id="metadata49"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
id="defs47" /><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1293"
inkscape:window-height="921"
id="namedview45"
showgrid="false"
inkscape:zoom="0.4609375"
inkscape:cx="256"
inkscape:cy="256"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="0"
inkscape:current-layer="Layer_1" /><g
id="g3"
transform="matrix(0.87890453,0,0,0.87890625,30,32)"><g
id="g5"><g
id="g7"><path
style="fill:#484848"
d="M 506.513,98.709 413.291,5.486 C 409.78,1.974 405.014,0 400.047,0 L 385.77,0 c -3.448,0 -6.244,2.796 -6.244,6.244 l 0,151.114 c 0,10.345 -8.387,18.732 -18.732,18.732 l -209.598,0 c -10.345,0 -18.732,-8.387 -18.732,-18.732 l 0,-151.114 C 132.464,2.796 129.668,0 126.22,0 L 18.732,0 C 8.387,0 0,8.387 0,18.732 L 0,493.269 C 0,503.613 8.387,512 18.732,512 l 474.537,0 c 10.345,0 18.732,-8.387 18.732,-18.732 l 0,-381.314 C 512,106.987 510.027,102.221 506.513,98.709 Z M 400.554,410.226 c 0,10.345 -8.387,18.732 -18.732,18.732 l -251.644,0 c -10.345,0 -18.732,-8.387 -18.732,-18.732 l 0,-147.132 c 0,-10.345 8.387,-18.732 18.732,-18.732 l 251.644,0 c 10.345,0 18.732,8.387 18.732,18.732 l 0,147.132 z"
id="path9"
inkscape:connector-curvature="0" /><path
style="fill:#f44336"
d="m 176.172,126.138 159.647,0 c 3.449,0 6.244,-2.796 6.244,-6.244 l 0,-113.65 C 342.063,2.796 339.267,0 335.819,0 L 176.172,0 c -3.448,0 -6.244,2.796 -6.244,6.244 l 0,113.65 c 0,3.448 2.796,6.244 6.244,6.244 z M 275.346,46.27 c 0,-10.345 8.387,-18.732 18.732,-18.732 10.345,0 18.732,8.387 18.732,18.732 l 0,33.598 c 0,10.345 -8.387,18.732 -18.732,18.732 -10.345,0 -18.732,-8.387 -18.732,-18.732 l 0,-33.598 z"
id="path11"
inkscape:connector-curvature="0" /><path
style="fill:#f44336"
d="m 318.413,317.93 -124.827,0 c -10.345,0 -18.732,8.387 -18.732,18.732 0,10.345 8.387,18.732 18.732,18.732 l 124.828,0 c 10.345,0 18.73,-8.387 18.73,-18.732 0,-10.345 -8.386,-18.732 -18.731,-18.732 z"
id="path13"
inkscape:connector-curvature="0" /></g></g></g><g
id="g15" /><g
id="g17" /><g
id="g19" /><g
id="g21" /><g
id="g23" /><g
id="g25" /><g
id="g27" /><g
id="g29" /><g
id="g31" /><g
id="g33" /><g
id="g35" /><g
id="g37" /><g
id="g39" /><g
id="g41" /><g
id="g43" /></svg>

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 47 47" style="enable-background:new 0 0 47 47;" xml:space="preserve">
<g>
<path fill="#484848" d="M46.368,43.354l-7.177-7.178c-0.476-0.475-1.117-0.67-1.737-0.604l-1.005-1.006c3.353-3.803,5.204-8.623,5.204-13.736
c0-5.563-2.166-10.793-6.1-14.727C31.618,2.167,26.388,0,20.825,0S10.03,2.167,6.097,6.102c-8.122,8.12-8.122,21.335,0,29.457
c3.934,3.935,9.164,6.101,14.727,6.101c5.115,0,9.934-1.851,13.738-5.204l1.005,1.005c-0.066,0.62,0.129,1.263,0.604,1.737
l7.178,7.177C43.765,46.791,44.312,47,44.857,47s1.094-0.208,1.51-0.626C47.203,45.54,47.203,44.188,46.368,43.354z
M20.824,37.386c-4.421,0-8.578-1.722-11.706-4.849c-6.456-6.456-6.456-16.96,0-23.415c3.128-3.127,7.285-4.85,11.707-4.85
c4.421,0,8.58,1.723,11.708,4.851c3.127,3.127,4.849,7.285,4.849,11.706c0,4.422-1.723,8.579-4.852,11.706
C29.403,35.664,25.245,37.386,20.824,37.386z"/>
<path fill="#f44336" d="M33.258,25.352L26.85,20.01c-0.319-0.266-0.764-0.322-1.138-0.147c-0.375,0.176-0.614,0.553-0.614,0.967v2.258h-5.341
c-0.59,0-1.068,0.479-1.068,1.068v4.023c0,0.59,0.478,1.068,1.068,1.068h5.341v2.261c0,0.415,0.239,0.792,0.614,0.968
c0.146,0.067,0.3,0.102,0.453,0.102c0.245,0,0.488-0.084,0.685-0.248l6.408-5.34c0.243-0.203,0.385-0.504,0.385-0.82
S33.501,25.555,33.258,25.352z"/>
<path fill="#484848" d="M22.96,17.5v-4.023c0-0.59-0.478-1.068-1.068-1.068h-5.339V10.15c0-0.415-0.24-0.792-0.615-0.968
c-0.376-0.175-0.819-0.118-1.137,0.146l-6.411,5.341c-0.244,0.203-0.384,0.503-0.384,0.821c0,0.317,0.141,0.618,0.384,0.821
l6.411,5.341c0.195,0.163,0.438,0.248,0.684,0.248c0.154,0,0.309-0.034,0.454-0.101c0.375-0.177,0.615-0.553,0.615-0.968v-2.263
h5.339C22.482,18.567,22.96,18.089,22.96,17.5z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 47 47" style="enable-background:new 0 0 47 47;" xml:space="preserve">
<g>
<path fill="#484848" d="M46.368,43.354l-7.177-7.178c-0.476-0.475-1.117-0.67-1.737-0.604l-1.005-1.006c3.353-3.803,5.204-8.623,5.204-13.736
c0-5.563-2.166-10.793-6.1-14.727C31.618,2.167,26.388,0,20.825,0S10.03,2.167,6.097,6.102c-8.122,8.12-8.122,21.335,0,29.457
c3.934,3.935,9.164,6.101,14.727,6.101c5.115,0,9.934-1.851,13.738-5.204l1.005,1.005c-0.066,0.62,0.129,1.263,0.604,1.737
l7.178,7.177C43.765,46.791,44.312,47,44.857,47s1.094-0.208,1.51-0.626C47.203,45.54,47.203,44.188,46.368,43.354z
M20.824,37.386c-4.421,0-8.578-1.722-11.706-4.849c-6.456-6.456-6.456-16.96,0-23.415c3.128-3.127,7.285-4.85,11.707-4.85
c4.421,0,8.58,1.723,11.708,4.851c3.127,3.127,4.849,7.285,4.849,11.706c0,4.422-1.723,8.579-4.852,11.706
C29.403,35.664,25.245,37.386,20.824,37.386z"/>
<path fill="#484848" d="M33.258,25.352L26.85,20.01c-0.319-0.266-0.764-0.322-1.138-0.147c-0.375,0.176-0.614,0.553-0.614,0.967v2.258h-5.341
c-0.59,0-1.068,0.479-1.068,1.068v4.023c0,0.59,0.478,1.068,1.068,1.068h5.341v2.261c0,0.415,0.239,0.792,0.614,0.968
c0.146,0.067,0.3,0.102,0.453,0.102c0.245,0,0.488-0.084,0.685-0.248l6.408-5.34c0.243-0.203,0.385-0.504,0.385-0.82
S33.501,25.555,33.258,25.352z"/>
<path fill="#f44336" d="M22.96,17.5v-4.023c0-0.59-0.478-1.068-1.068-1.068h-5.339V10.15c0-0.415-0.24-0.792-0.615-0.968
c-0.376-0.175-0.819-0.118-1.137,0.146l-6.411,5.341c-0.244,0.203-0.384,0.503-0.384,0.821c0,0.317,0.141,0.618,0.384,0.821
l6.411,5.341c0.195,0.163,0.438,0.248,0.684,0.248c0.154,0,0.309-0.034,0.454-0.101c0.375-0.177,0.615-0.553,0.615-0.968v-2.263
h5.339C22.482,18.567,22.96,18.089,22.96,17.5z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -0,0 +1,39 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 932.179 932.179" style="enable-background:new 0 0 932.179 932.179;" xml:space="preserve">
<g>
<path fill="#484848" d="M61.2,341.538c4.9,16.8,11.7,33,20.3,48.2l-24.5,30.9c-8,10.1-7.1,24.5,1.9,33.6l42.2,42.2c9.1,9.1,23.5,9.899,33.6,1.899
l30.7-24.3c15.8,9.101,32.6,16.2,50.1,21.2l4.6,39.5c1.5,12.8,12.3,22.4,25.1,22.4h59.7c12.8,0,23.6-9.601,25.1-22.4l4.4-38.1
c18.8-4.9,36.8-12.2,53.7-21.7l29.7,23.5c10.1,8,24.5,7.1,33.6-1.9l42.2-42.2c9.1-9.1,9.9-23.5,1.9-33.6l-23.1-29.3
c9.6-16.601,17.1-34.3,22.1-52.8l35.6-4.1c12.801-1.5,22.4-12.3,22.4-25.1v-59.7c0-12.8-9.6-23.6-22.4-25.1l-35.1-4.1
c-4.801-18.3-12-35.8-21.199-52.2l21.6-27.3c8-10.1,7.1-24.5-1.9-33.6l-42.1-42.1c-9.1-9.1-23.5-9.9-33.6-1.9l-26.5,21
c-17.2-10.1-35.601-17.8-54.9-23l-4-34.3c-1.5-12.8-12.3-22.4-25.1-22.4h-59.7c-12.8,0-23.6,9.6-25.1,22.4l-4,34.3
c-19.8,5.3-38.7,13.3-56.3,23.8l-27.5-21.8c-10.1-8-24.5-7.1-33.6,1.9l-42.2,42.2c-9.1,9.1-9.9,23.5-1.9,33.6l23,29.1
c-9.2,16.6-16.2,34.3-20.8,52.7l-36.8,4.2c-12.8,1.5-22.4,12.3-22.4,25.1v59.7c0,12.8,9.6,23.6,22.4,25.1L61.2,341.538z
M277.5,180.038c54.4,0,98.7,44.3,98.7,98.7s-44.3,98.7-98.7,98.7c-54.399,0-98.7-44.3-98.7-98.7S223.1,180.038,277.5,180.038z"/>
<path fill="#f44336" d="M867.699,356.238l-31.5-26.6c-9.699-8.2-24-7.8-33.199,0.9l-17.4,16.3c-14.699-7.1-30.299-12.1-46.4-15l-4.898-24
c-2.5-12.4-14-21-26.602-20l-41.1,3.5c-12.6,1.1-22.5,11.4-22.9,24.1l-0.799,24.4c-15.801,5.7-30.701,13.5-44.301,23.3
l-20.799-13.8c-10.602-7-24.701-5-32.9,4.7l-26.6,31.7c-8.201,9.7-7.801,24,0.898,33.2l18.201,19.399
c-6.301,14.2-10.801,29.101-13.4,44.4l-26,5.3c-12.4,2.5-21,14-20,26.601l3.5,41.1c1.1,12.6,11.4,22.5,24.1,22.9l28.1,0.899
c5.102,13.4,11.801,26.101,19.9,38l-15.699,23.7c-7,10.6-5,24.7,4.699,32.9l31.5,26.6c9.701,8.2,24,7.8,33.201-0.9l20.6-19.3
c13.5,6.3,27.699,11,42.299,13.8l5.701,28.2c2.5,12.4,14,21,26.6,20l41.1-3.5c12.6-1.1,22.5-11.399,22.9-24.1l0.9-27.601
c15-5.3,29.199-12.5,42.299-21.399l22.701,15c10.6,7,24.699,5,32.9-4.7l26.6-31.5c8.199-9.7,7.799-24-0.9-33.2l-18.301-19.399
c6.701-14.2,11.602-29.2,14.4-44.601l25-5.1c12.4-2.5,21-14,20-26.601l-3.5-41.1c-1.1-12.6-11.4-22.5-24.1-22.9l-25.1-0.8
c-5.201-14.6-12.201-28.399-20.9-41.2l13.699-20.6C879.4,378.638,877.4,364.438,867.699,356.238z M712.801,593.837
c-44.4,3.801-83.602-29.3-87.301-73.699c-3.801-44.4,29.301-83.601,73.699-87.301c44.4-3.8,83.602,29.301,87.301,73.7
C790.301,550.938,757.199,590.138,712.801,593.837z"/>
<path fill="#484848" d="M205,704.438c-12.6,1.3-22.3,11.899-22.4,24.6l-0.3,25.3c-0.2,12.7,9.2,23.5,21.8,25.101l18.6,2.399
c3.1,11.301,7.5,22.101,13.2,32.301l-12,14.8c-8,9.899-7.4,24.1,1.5,33.2l17.7,18.1c8.9,9.1,23.1,10.1,33.2,2.3l14.899-11.5
c10.5,6.2,21.601,11.101,33.2,14.5l2,19.2c1.3,12.6,11.9,22.3,24.6,22.4l25.301,0.3c12.699,0.2,23.5-9.2,25.1-21.8l2.3-18.2
c12.601-3.101,24.601-7.8,36-14l14,11.3c9.9,8,24.101,7.4,33.201-1.5l18.1-17.7c9.1-8.899,10.1-23.1,2.301-33.2L496.6,818.438
c6.6-11,11.701-22.7,15.201-35l16.6-1.7c12.6-1.3,22.299-11.9,22.4-24.6l0.299-25.301c0.201-12.699-9.199-23.5-21.799-25.1
l-16.201-2.1c-3.1-12.2-7.699-24-13.699-35l10.1-12.4c8-9.9,7.4-24.1-1.5-33.2l-17.699-18.1c-8.9-9.101-23.102-10.101-33.201-2.3
l-12.101,9.3c-11.399-6.9-23.6-12.2-36.399-15.8l-1.601-15.7c-1.3-12.601-11.899-22.3-24.6-22.4l-25.3-0.3
c-12.7-0.2-23.5,9.2-25.101,21.8l-2,15.601c-13.199,3.399-25.899,8.6-37.699,15.399l-12.5-10.2c-9.9-8-24.101-7.399-33.201,1.5
l-18.2,17.801c-9.1,8.899-10.1,23.1-2.3,33.199l10.7,13.801c-6.2,11-11.1,22.699-14.3,35L205,704.438z M368.3,675.837
c36.3,0.4,65.399,30.301,65,66.601c-0.4,36.3-30.301,65.399-66.601,65c-36.3-0.4-65.399-30.3-65-66.601
C302.1,704.538,332,675.438,368.3,675.837z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.0 KiB

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 372.465 372.465" style="enable-background:new 0 0 372.465 372.465;" xml:space="preserve">
<g>
<path fill="#484848" d="M101.98,186.441H30.484c-5.523,0-10,4.477-10,10v166.021c0,5.523,4.477,10,10,10h71.496c5.523,0,10-4.477,10-10V196.441
C111.98,190.919,107.503,186.441,101.98,186.441z"/>
<path fill="#f44336" d="M221.98,0h-71.496c-5.523,0-10,4.477-10,10v352.465c0,5.521,4.477,10,10,10h71.496c5.523,0,10-4.479,10-10V10
C231.98,4.477,227.504,0,221.98,0z"/>
<path fill="#484848" d="M341.98,115.257h-71.496c-5.523,0-10,4.477-10,10v237.208c0,5.521,4.477,10,10,10h71.496c5.523,0,10-4.479,10-10V125.257
C351.98,119.734,347.504,115.257,341.98,115.257z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 482 482" style="enable-background:new 0 0 482 482;" xml:space="preserve">
<g>
<path fill="#484848" d="M123.7,216.8H13.5c-7.5,0-13.5,6-13.5,13.5v225.4c0,7.5,6,13.5,13.5,13.5h110.2c7.5,0,13.5-6,13.5-13.5V230.3
C137.2,222.8,131.2,216.8,123.7,216.8z M110.2,442.2H27V243.8h83.2V442.2z"/>
<path fill="#484848" d="M296.1,12.8H185.9c-7.5,0-13.5,6-13.5,13.5v429.4c0,7.5,6,13.5,13.5,13.5h110.2c7.5,0,13.5-6,13.5-13.5V26.3
C309.6,18.9,303.6,12.8,296.1,12.8z M199.4,39.8h25.3l-25.3,25.3V39.8z M282.6,442.2h-22.7l22.7-22.7V442.2z M282.6,381.3
c-0.1,0.1-0.1,0.1-0.2,0.2l-60.7,60.7h-22.3v-37.5l83.2-83.2L282.6,381.3L282.6,381.3z M282.6,283.4c-0.1,0.1-0.1,0.1-0.2,0.2
l-83,83v-67.7l83.2-83.2L282.6,283.4L282.6,283.4z M282.6,177.5c-0.1,0.1-0.1,0.1-0.2,0.2l-83,83v-57.5l83.2-83.2L282.6,177.5
L282.6,177.5z M282.6,81.8c-0.1,0.1-0.1,0.1-0.2,0.2l-83,83v-61.7l63.1-63.1c0.1-0.1,0.2-0.3,0.4-0.4h19.7V81.8z"/>
<path fill="#484848" d="M468.5,153H358.3c-7.5,0-13.5,6-13.5,13.5v289.2c0,7.5,6,13.5,13.5,13.5h110.2c7.5,0,13.5-6,13.5-13.5V166.5
C482,159,475.9,153,468.5,153z M455,442.2h-83.2V180H455V442.2z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 510 510" style="enable-background:new 0 0 510 510;" xml:space="preserve">
<g>
<path fill="#f44336" d="M178.5,357h-25.5V153h204V357z"/>
<path fill="#484848" d="M255,0C114.75,0,0,114.75,0,255s114.75,255,255,255s255-114.75,255-255S395.25,0,255,0z
M255,459c-112.2,0-204-91.8-204-204S142.8,51,255,51s204,91.8,204,204S367.2,459,255,459z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 741 B

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 18.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 233.576 233.576" style="enable-background:new 0 0 233.576 233.576;" xml:space="preserve">
<g>
<path fill="#484848" d="M176.982,129.274c-16.066-16.113-37.442-24.986-60.193-24.986s-44.128,8.873-60.193,24.986l-21.244-21.182
c21.735-21.799,50.657-33.805,81.438-33.805c30.781,0,59.703,12.005,81.438,33.805L176.982,129.274z"/>
<path fill="#484848" d="M116.788,54.288
c36.109,0,70.045,14.076,95.554,39.636l21.234-21.192c-31.178-31.239-72.654-48.444-116.788-48.444
C72.653,24.288,31.178,41.493,0,72.732l21.234,21.192C46.743,68.364,80.678,54.288,116.788,54.288z"/>
<path fill="#484848" d="M162.885,143.465
c-12.293-12.367-28.664-19.177-46.097-19.177c-17.432,0-33.803,6.811-46.097,19.177l21.275,21.151
c6.621-6.66,15.437-10.328,24.821-10.328c9.386,0,18.2,3.667,24.819,10.327L162.885,143.465z"/>
<path fill="#f44336" d="M116.788,169.288
c-11.046,0-20,8.954-20,20s8.954,20,20,20c11.044,0,20-8.954,20-20S127.832,169.288,116.788,169.288z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 18.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 233.576 233.576" style="enable-background:new 0 0 233.576 233.576;" xml:space="preserve">
<g>
<path fill="#4caf50" d="M176.982,129.274c-16.066-16.113-37.442-24.986-60.193-24.986s-44.128,8.873-60.193,24.986l-21.244-21.182
c21.735-21.799,50.657-33.805,81.438-33.805c30.781,0,59.703,12.005,81.438,33.805L176.982,129.274z"/>
<path fill="#4caf50" d="M116.788,54.288
c36.109,0,70.045,14.076,95.554,39.636l21.234-21.192c-31.178-31.239-72.654-48.444-116.788-48.444
C72.653,24.288,31.178,41.493,0,72.732l21.234,21.192C46.743,68.364,80.678,54.288,116.788,54.288z"/>
<path fill="#4caf50" d="M162.885,143.465
c-12.293-12.367-28.664-19.177-46.097-19.177c-17.432,0-33.803,6.811-46.097,19.177l21.275,21.151
c6.621-6.66,15.437-10.328,24.821-10.328c9.386,0,18.2,3.667,24.819,10.327L162.885,143.465z"/>
<path fill="#f44336" d="M116.788,169.288
c-11.046,0-20,8.954-20,20s8.954,20,20,20c11.044,0,20-8.954,20-20S127.832,169.288,116.788,169.288z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -0,0 +1,85 @@
/************************************************************************
* file name : main.cpp
* ----------------- :
* creation time : 2016/04/29
* authors : Sergey Yagovtsev, Victor Zarubkin
* email : yse.sey@gmail.com, v.s.zarubkin@gmail.com
* ----------------- :
* description : Main file for EasyProfiler GUI.
* ----------------- :
* license : Lightweight profiler library for c++
* : Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
* :
* :
* : Licensed under the Apache License, Version 2.0 (the "License");
* : you may not use this file except in compliance with the License.
* : You may obtain a copy of the License at
* :
* : http://www.apache.org/licenses/LICENSE-2.0
* :
* : Unless required by applicable law or agreed to in writing, software
* : distributed under the License is distributed on an "AS IS" BASIS,
* : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* : See the License for the specific language governing permissions and
* : limitations under the License.
* :
* :
* : GNU General Public License Usage
* : Alternatively, this file may be used under the terms of the GNU
* : General Public License as published by the Free Software Foundation,
* : either version 3 of the License, or (at your option) any later version.
* :
* : This program is distributed in the hope that it will be useful,
* : but WITHOUT ANY WARRANTY; without even the implied warranty of
* : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
* : GNU General Public License for more details.
* :
* : You should have received a copy of the GNU General Public License
* : along with this program.If not, see <http://www.gnu.org/licenses/>.
************************************************************************/
#include <chrono>
#include <QApplication>
//#include <QTreeView>
//#include <QFileSystemModel>
//#include "treemodel.h"
#include "main_window.h"
#include "easy/reader.h"
#if defined(_WIN32) && defined (_BUILD_RELEASE_)
#pragma comment(linker, "/SUBSYSTEM:windows /ENTRY:mainCRTStartup")
#endif
int main(int argc, char **argv)
{
QApplication app(argc, argv);
//QFileSystemModel *model = new QFileSystemModel;
//model->setRootPath(QDir::currentPath());
// const char* filename = 0;
// if(argc > 1 && argv[1]){
// filename = argv[1];
// }else{
// return 255;
// }
// QFile file(filename);
// file.open(QIODevice::ReadOnly);
// TreeModel model(file.readAll());
// file.close();
// QTreeView *tree = new QTreeView();
// tree->setModel(&model);
//
// tree->show();
auto now = ::std::chrono::duration_cast<std::chrono::seconds>(::std::chrono::system_clock::now().time_since_epoch()).count() >> 1;
srand((unsigned int)now);
EasyMainWindow window;
window.show();
return app.exec();
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,288 @@
/************************************************************************
* file name : main_window.h
* ----------------- :
* creation time : 2016/06/26
* author : Victor Zarubkin
* email : v.s.zarubkin@gmail.com
* ----------------- :
* description : The file contains declaration of MainWindow for easy_profiler GUI.
* ----------------- :
* change log : * 2016/06/26 Victor Zarubkin: initial commit.
* : *
* ----------------- :
* license : Lightweight profiler library for c++
* : Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
* :
* :
* : Licensed under the Apache License, Version 2.0 (the "License");
* : you may not use this file except in compliance with the License.
* : You may obtain a copy of the License at
* :
* : http://www.apache.org/licenses/LICENSE-2.0
* :
* : Unless required by applicable law or agreed to in writing, software
* : distributed under the License is distributed on an "AS IS" BASIS,
* : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* : See the License for the specific language governing permissions and
* : limitations under the License.
* :
* :
* : GNU General Public License Usage
* : Alternatively, this file may be used under the terms of the GNU
* : General Public License as published by the Free Software Foundation,
* : either version 3 of the License, or (at your option) any later version.
* :
* : This program is distributed in the hope that it will be useful,
* : but WITHOUT ANY WARRANTY; without even the implied warranty of
* : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
* : GNU General Public License for more details.
* :
* : You should have received a copy of the GNU General Public License
* : along with this program.If not, see <http://www.gnu.org/licenses/>.
************************************************************************/
#ifndef EASY_PROFILER_GUI__MAIN_WINDOW__H
#define EASY_PROFILER_GUI__MAIN_WINDOW__H
#include <string>
#include <thread>
#include <atomic>
#include <sstream>
#include <QMainWindow>
#include <QTimer>
#include <QStringList>
#include "easy/easy_socket.h"
#include "easy/reader.h"
#ifdef max
#undef max
#endif
#ifdef min
#undef min
#endif
//////////////////////////////////////////////////////////////////////////
#define EASY_GUI_USE_DESCRIPTORS_DOCK_WINDOW 0
class QDockWidget;
namespace profiler { namespace net { struct EasyProfilerStatus; } }
//////////////////////////////////////////////////////////////////////////
class EasyFileReader Q_DECL_FINAL
{
::profiler::SerializedData m_serializedBlocks; ///<
::profiler::SerializedData m_serializedDescriptors; ///<
::profiler::descriptors_list_t m_descriptors; ///<
::profiler::blocks_t m_blocks; ///<
::profiler::thread_blocks_tree_t m_blocksTree; ///<
::std::stringstream m_stream; ///<
::std::stringstream m_errorMessage; ///<
QString m_filename; ///<
uint32_t m_descriptorsNumberInFile = 0; ///<
::std::thread m_thread; ///<
::std::atomic_bool m_bDone; ///<
::std::atomic<int> m_progress; ///<
::std::atomic<unsigned int> m_size; ///<
bool m_isFile = false; ///<
public:
EasyFileReader();
~EasyFileReader();
const bool isFile() const;
bool done() const;
int progress() const;
unsigned int size() const;
const QString& filename() const;
void load(const QString& _filename);
void load(::std::stringstream& _stream);
void interrupt();
void get(::profiler::SerializedData& _serializedBlocks, ::profiler::SerializedData& _serializedDescriptors,
::profiler::descriptors_list_t& _descriptors, ::profiler::blocks_t& _blocks, ::profiler::thread_blocks_tree_t& _tree,
uint32_t& _descriptorsNumberInFile, QString& _filename);
QString getError();
}; // END of class EasyFileReader.
//////////////////////////////////////////////////////////////////////////
enum EasyListenerRegime : uint8_t
{
LISTENER_IDLE = 0,
LISTENER_CAPTURE,
LISTENER_DESCRIBE
};
class EasySocketListener Q_DECL_FINAL
{
EasySocket m_easySocket; ///<
::std::string m_address; ///<
::std::stringstream m_receivedData; ///<
::std::thread m_thread; ///<
uint64_t m_receivedSize; ///<
uint16_t m_port; ///<
::std::atomic_bool m_bInterrupt; ///<
::std::atomic_bool m_bConnected; ///<
::std::atomic_bool m_bStopReceive; ///<
EasyListenerRegime m_regime; ///<
public:
EasySocketListener();
~EasySocketListener();
bool connected() const;
EasyListenerRegime regime() const;
uint64_t size() const;
const ::std::string& address() const;
uint16_t port() const;
::std::stringstream& data();
void clearData();
bool connect(const char* _ipaddress, uint16_t _port, ::profiler::net::EasyProfilerStatus& _reply);
bool startCapture();
void stopCapture();
void requestBlocksDescription();
template <class T>
inline void send(const T& _message) {
m_easySocket.send(&_message, sizeof(T));
}
private:
void listenCapture();
void listenDescription();
}; // END of class EasySocketListener.
//////////////////////////////////////////////////////////////////////////
class EasyMainWindow : public QMainWindow
{
Q_OBJECT
protected:
typedef EasyMainWindow This;
typedef QMainWindow Parent;
QStringList m_lastFiles;
QString m_lastAddress;
QDockWidget* m_treeWidget = nullptr;
QDockWidget* m_graphicsView = nullptr;
#if EASY_GUI_USE_DESCRIPTORS_DOCK_WINDOW != 0
QDockWidget* m_descTreeWidget = nullptr;
#endif
class QProgressDialog* m_progress = nullptr;
class QDialog* m_descTreeDialog = nullptr;
class EasyDescWidget* m_dialogDescTree = nullptr;
class QMessageBox* m_listenerDialog = nullptr;
QTimer m_readerTimer;
QTimer m_listenerTimer;
::profiler::SerializedData m_serializedBlocks;
::profiler::SerializedData m_serializedDescriptors;
EasyFileReader m_reader;
EasySocketListener m_listener;
class QLineEdit* m_addressEdit = nullptr;
class QLineEdit* m_portEdit = nullptr;
class QLineEdit* m_frameTimeEdit = nullptr;
class QMenu* m_loadActionMenu = nullptr;
class QAction* m_saveAction = nullptr;
class QAction* m_deleteAction = nullptr;
class QAction* m_captureAction = nullptr;
class QAction* m_connectAction = nullptr;
class QAction* m_eventTracingEnableAction = nullptr;
class QAction* m_eventTracingPriorityAction = nullptr;
uint32_t m_descriptorsNumberInFile = 0;
uint16_t m_lastPort = 0;
bool m_bNetworkFileRegime = false;
public:
explicit EasyMainWindow();
virtual ~EasyMainWindow();
// Public virtual methods
void closeEvent(QCloseEvent* close_event) override;
void dragEnterEvent(QDragEnterEvent* drag_event) override;
void dragMoveEvent(QDragMoveEvent* drag_event) override;
void dragLeaveEvent(QDragLeaveEvent* drag_event) override;
void dropEvent(QDropEvent* drop_event) override;
protected slots:
void onOpenFileClicked(bool);
void onSaveFileClicked(bool);
void onDeleteClicked(bool);
void onExitClicked(bool);
void onEncodingChanged(bool);
void onChronoTextPosChanged(bool);
void onUnitsChanged(bool);
void onEventIndicatorsChange(bool);
void onEnableDisableStatistics(bool);
void onCollapseItemsAfterCloseChanged(bool);
void onAllItemsExpandedByDefaultChange(bool);
void onBindExpandStatusChange(bool);
void onHierarchyFlagChange(bool);
void onExpandAllClicked(bool);
void onCollapseAllClicked(bool);
void onSpacingChange(int _value);
void onMinSizeChange(int _value);
void onNarrowSizeChange(int _value);
void onFileReaderTimeout();
void onListenerTimerTimeout();
void onFileReaderCancel();
void onEditBlocksClicked(bool);
void onDescTreeDialogClose(int);
void onListenerDialogClose(int);
void onCaptureClicked(bool);
void onGetBlockDescriptionsClicked(bool);
void onConnectClicked(bool);
void onEventTracingPriorityChange(bool _checked);
void onEventTracingEnableChange(bool _checked);
void onFrameTimeEditFinish();
void onBlockStatusChange(::profiler::block_id_t _id, ::profiler::EasyBlockStatus _status);
private:
// Private non-virtual methods
void clear();
void refreshDiagram();
void addFileToList(const QString& filename);
void loadFile(const QString& filename);
void readStream(::std::stringstream& data);
void loadSettings();
void loadGeometry();
void saveSettingsAndGeometry();
void setDisconnected(bool _showMessage = true);
}; // END of class EasyMainWindow.
//////////////////////////////////////////////////////////////////////////
#endif // EASY_PROFILER_GUI__MAIN_WINDOW__H

View File

@ -0,0 +1,29 @@
<!DOCTYPE RCC><RCC version="1.0">
<qresource>
<file alias="logo">icons/logo.svg</file>
<file alias="Exit">icons/off.svg</file>
<file alias="Open">icons/open-folder2.svg</file>
<file alias="Reopen">icons/reload-folder2.svg</file>
<file alias="Reload">icons/reload.svg</file>
<file alias="Expand">icons/expand.svg</file>
<file alias="Collapse">icons/collapse.svg</file>
<file alias="Color">icons/colors.svg</file>
<file alias="NoColor">icons/colors-black.svg</file>
<file alias="Save">icons/save.svg</file>
<file alias="Stats">icons/statistics.svg</file>
<file alias="Stats-off">icons/statistics2.svg</file>
<file alias="LAN">icons/lan.svg</file>
<file alias="LAN-on">icons/lan_on.svg</file>
<file alias="WiFi">icons/wifi.svg</file>
<file alias="WiFi-on">icons/wifi_on.svg</file>
<file alias="Connection">icons/lan.svg</file>
<file alias="Connection-on">icons/lan_on.svg</file>
<file alias="Start">icons/play.svg</file>
<file alias="Stop">icons/stop.svg</file>
<file alias="Delete">icons/delete.svg</file>
<file alias="List">icons/list.svg</file>
<file alias="Search-next">icons/search-next.svg</file>
<file alias="Search-prev">icons/search-prev.svg</file>
<file alias="Settings">icons/settings.svg</file>
</qresource>
</RCC>

View File

@ -0,0 +1,33 @@
IDI_ICON1 ICON DISCARDABLE "icons/logo.ico"
1 VERSIONINFO
FILEVERSION EASY_PROFILER_VERSION_MAJOR, EASY_PROFILER_VERSION_MINOR, EASY_PROFILER_VERSION_PATCH
PRODUCTVERSION EASY_PROFILER_VERSION_MAJOR, EASY_PROFILER_VERSION_MINOR, EASY_PROFILER_VERSION_PATCH
# define EASY_STRINGIFY(a) #a
# define EASY_STRINGIFICATION(a) EASY_STRINGIFY(a)
#define EASY_PROFILER_PRODUCT_VERSION "v" EASY_STRINGIFICATION(EASY_PROFILER_VERSION_MAJOR) "." \
EASY_STRINGIFICATION(EASY_PROFILER_VERSION_MINOR) "." \
EASY_STRINGIFICATION(EASY_PROFILER_VERSION_PATCH)
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "080904b0"
BEGIN
VALUE "CompanyName", "EasySolutions"
VALUE "FileDescription", "EasyProfiler"
VALUE "InternalName", "profiler_gui"
VALUE "LegalCopyright", "Copyright (C) 2016 Victor Zarubkin, Sergey Yagovtsev"
VALUE "LegalTrademarks1", "All Rights Reserved"
VALUE "LegalTrademarks2", "All Rights Reserved"
VALUE "OriginalFilename", "profiler_gui.exe"
VALUE "ProductName", "easy_profiler gui application"
VALUE "ProductVersion", EASY_PROFILER_PRODUCT_VERSION
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x809, 1200
END
END

View File

@ -0,0 +1,243 @@
/************************************************************************
* file name : tree_widget_item.cpp
* ----------------- :
* creation time : 2016/08/18
* author : Victor Zarubkin
* email : v.s.zarubkin@gmail.com
* ----------------- :
* description : The file contains implementation of EasyTreeWidgetItem.
* ----------------- :
* change log : * 2016/08/18 Victor Zarubkin: Moved sources from blocks_tree_widget.cpp
* : and renamed classes from Prof* to Easy*.
* :
* : *
* ----------------- :
* license : Lightweight profiler library for c++
* : Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
* :
* :
* : Licensed under the Apache License, Version 2.0 (the "License");
* : you may not use this file except in compliance with the License.
* : You may obtain a copy of the License at
* :
* : http://www.apache.org/licenses/LICENSE-2.0
* :
* : Unless required by applicable law or agreed to in writing, software
* : distributed under the License is distributed on an "AS IS" BASIS,
* : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* : See the License for the specific language governing permissions and
* : limitations under the License.
* :
* :
* : GNU General Public License Usage
* : Alternatively, this file may be used under the terms of the GNU
* : General Public License as published by the Free Software Foundation,
* : either version 3 of the License, or (at your option) any later version.
* :
* : This program is distributed in the hope that it will be useful,
* : but WITHOUT ANY WARRANTY; without even the implied warranty of
* : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
* : GNU General Public License for more details.
* :
* : You should have received a copy of the GNU General Public License
* : along with this program.If not, see <http://www.gnu.org/licenses/>.
************************************************************************/
#include "tree_widget_item.h"
#include "globals.h"
//////////////////////////////////////////////////////////////////////////
EasyTreeWidgetItem::EasyTreeWidgetItem(const ::profiler::block_index_t _treeBlock, Parent* _parent)
: Parent(_parent)
, m_block(_treeBlock)
, m_customBGColor(0)
, m_customTextColor(0)
{
}
EasyTreeWidgetItem::~EasyTreeWidgetItem()
{
}
bool EasyTreeWidgetItem::operator < (const Parent& _other) const
{
const auto col = treeWidget()->sortColumn();
switch (col)
{
//case COL_UNKNOWN:
case COL_NAME:
{
if (parent() == nullptr)
return false; // Do not sort topLevelItems by name
return Parent::operator < (_other);
}
case COL_NCALLS_PER_THREAD:
case COL_NCALLS_PER_PARENT:
case COL_NCALLS_PER_FRAME:
{
return data(col, Qt::UserRole).toUInt() < _other.data(col, Qt::UserRole).toUInt();
}
case COL_SELF_DURATION_PERCENT:
case COL_PERCENT_PER_PARENT:
case COL_PERCENT_PER_FRAME:
case COL_PERCENT_SUM_PER_PARENT:
case COL_PERCENT_SUM_PER_FRAME:
case COL_PERCENT_SUM_PER_THREAD:
{
return data(col, Qt::UserRole).toInt() < _other.data(col, Qt::UserRole).toInt();
}
case COL_ACTIVE_PERCENT:
{
return data(col, Qt::UserRole).toDouble() < _other.data(col, Qt::UserRole).toDouble();
}
default:
{
// durations min, max, average
return data(col, Qt::UserRole).toULongLong() < _other.data(col, Qt::UserRole).toULongLong();
}
}
return false;
}
::profiler::block_index_t EasyTreeWidgetItem::block_index() const
{
return m_block;
}
::profiler_gui::EasyBlock& EasyTreeWidgetItem::guiBlock()
{
return easyBlock(m_block);
}
const ::profiler::BlocksTree& EasyTreeWidgetItem::block() const
{
return blocksTree(m_block);
}
::profiler::timestamp_t EasyTreeWidgetItem::duration() const
{
if (parent() != nullptr)
return block().node->duration();
return data(COL_DURATION, Qt::UserRole).toULongLong();
}
::profiler::timestamp_t EasyTreeWidgetItem::selfDuration() const
{
return data(COL_SELF_DURATION, Qt::UserRole).toULongLong();
}
void EasyTreeWidgetItem::setTimeSmart(int _column, ::profiler_gui::TimeUnits _units, const ::profiler::timestamp_t& _time, const QString& _prefix)
{
const ::profiler::timestamp_t nanosecondsTime = PROF_NANOSECONDS(_time);
setData(_column, Qt::UserRole, (quint64)nanosecondsTime);
setToolTip(_column, QString("%1 ns").arg(nanosecondsTime));
setText(_column, QString("%1%2").arg(_prefix).arg(::profiler_gui::timeStringRealNs(_units, nanosecondsTime, 3)));
// if (_time < 1e3)
// {
// setText(_column, QString("%1%2 ns").arg(_prefix).arg(nanosecondsTime));
// }
// else if (_time < 1e6)
// {
// setText(_column, QString("%1%2 us").arg(_prefix).arg(double(nanosecondsTime) * 1e-3, 0, 'f', 3));
// }
// else if (_time < 1e9)
// {
// setText(_column, QString("%1%2 ms").arg(_prefix).arg(double(nanosecondsTime) * 1e-6, 0, 'f', 3));
// }
// else
// {
// setText(_column, QString("%1%2 s").arg(_prefix).arg(double(nanosecondsTime) * 1e-9, 0, 'f', 3));
// }
}
void EasyTreeWidgetItem::setTimeSmart(int _column, ::profiler_gui::TimeUnits _units, const ::profiler::timestamp_t& _time)
{
const ::profiler::timestamp_t nanosecondsTime = PROF_NANOSECONDS(_time);
setData(_column, Qt::UserRole, (quint64)nanosecondsTime);
setToolTip(_column, QString("%1 ns").arg(nanosecondsTime));
setText(_column, ::profiler_gui::timeStringRealNs(_units, nanosecondsTime, 3));
}
void EasyTreeWidgetItem::setTimeMs(int _column, const ::profiler::timestamp_t& _time)
{
const ::profiler::timestamp_t nanosecondsTime = PROF_NANOSECONDS(_time);
setData(_column, Qt::UserRole, (quint64)nanosecondsTime);
setToolTip(_column, QString("%1 ns").arg(nanosecondsTime));
setText(_column, QString::number(double(nanosecondsTime) * 1e-6, 'g', 9));
}
void EasyTreeWidgetItem::setTimeMs(int _column, const ::profiler::timestamp_t& _time, const QString& _prefix)
{
const ::profiler::timestamp_t nanosecondsTime = PROF_NANOSECONDS(_time);
setData(_column, Qt::UserRole, (quint64)nanosecondsTime);
setToolTip(_column, QString("%1 ns").arg(nanosecondsTime));
setText(_column, QString("%1%2").arg(_prefix).arg(double(nanosecondsTime) * 1e-6, 0, 'g', 9));
}
void EasyTreeWidgetItem::setBackgroundColor(QRgb _color)
{
m_customBGColor = _color;
}
void EasyTreeWidgetItem::setTextColor(QRgb _color)
{
m_customTextColor = _color;
}
void EasyTreeWidgetItem::colorize(bool _colorize)
{
if (_colorize)
{
for (int i = 0; i < COL_COLUMNS_NUMBER; ++i)
{
setBackground(i, QColor::fromRgb(m_customBGColor));
setForeground(i, QColor::fromRgb(m_customTextColor));
}
}
else
{
const QBrush nobrush;
for (int i = 0; i < COL_COLUMNS_NUMBER; ++i)
{
setBackground(i, nobrush);
setForeground(i, nobrush);
}
}
}
void EasyTreeWidgetItem::collapseAll()
{
for (int i = 0, childrenNumber = childCount(); i < childrenNumber; ++i)
{
static_cast<EasyTreeWidgetItem*>(child(i))->collapseAll();
}
setExpanded(false);
if (parent() != nullptr)
guiBlock().expanded = false;
}
void EasyTreeWidgetItem::expandAll()
{
for (int i = 0, childrenNumber = childCount(); i < childrenNumber; ++i)
{
static_cast<EasyTreeWidgetItem*>(child(i))->expandAll();
}
setExpanded(true);
if (parent() != nullptr)
guiBlock().expanded = true;
}
//////////////////////////////////////////////////////////////////////////

View File

@ -0,0 +1,151 @@
/************************************************************************
* file name : tree_widget_item.h
* ----------------- :
* creation time : 2016/08/18
* author : Victor Zarubkin
* email : v.s.zarubkin@gmail.com
* ----------------- :
* description : The file contains declaration of EasyTreeWidgetItem
* : for displyaing EasyProfiler blocks tree.
* ----------------- :
* change log : * 2016/08/18 Victor Zarubkin: moved sources from blocks_tree_widget.h
* : and renamed classes from Prof* to Easy*.
* :
* : *
* ----------------- :
* license : Lightweight profiler library for c++
* : Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
* :
* :
* : Licensed under the Apache License, Version 2.0 (the "License");
* : you may not use this file except in compliance with the License.
* : You may obtain a copy of the License at
* :
* : http://www.apache.org/licenses/LICENSE-2.0
* :
* : Unless required by applicable law or agreed to in writing, software
* : distributed under the License is distributed on an "AS IS" BASIS,
* : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* : See the License for the specific language governing permissions and
* : limitations under the License.
* :
* :
* : GNU General Public License Usage
* : Alternatively, this file may be used under the terms of the GNU
* : General Public License as published by the Free Software Foundation,
* : either version 3 of the License, or (at your option) any later version.
* :
* : This program is distributed in the hope that it will be useful,
* : but WITHOUT ANY WARRANTY; without even the implied warranty of
* : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
* : GNU General Public License for more details.
* :
* : You should have received a copy of the GNU General Public License
* : along with this program.If not, see <http://www.gnu.org/licenses/>.
************************************************************************/
#ifndef EASY__TREE_WIDGET_ITEM__H_
#define EASY__TREE_WIDGET_ITEM__H_
#include <stdlib.h>
#include <QTreeWidget>
#include "easy/reader.h"
#include "common_types.h"
//////////////////////////////////////////////////////////////////////////
enum EasyColumnsIndexes
{
COL_UNKNOWN = -1,
COL_NAME = 0,
COL_BEGIN,
COL_DURATION,
COL_SELF_DURATION,
COL_DURATION_SUM_PER_PARENT,
COL_DURATION_SUM_PER_FRAME,
COL_DURATION_SUM_PER_THREAD,
COL_SELF_DURATION_PERCENT,
COL_PERCENT_PER_PARENT,
COL_PERCENT_PER_FRAME,
COL_PERCENT_SUM_PER_PARENT,
COL_PERCENT_SUM_PER_FRAME,
COL_PERCENT_SUM_PER_THREAD,
COL_END,
COL_MIN_PER_FRAME,
COL_MAX_PER_FRAME,
COL_AVERAGE_PER_FRAME,
COL_NCALLS_PER_FRAME,
COL_MIN_PER_THREAD,
COL_MAX_PER_THREAD,
COL_AVERAGE_PER_THREAD,
COL_NCALLS_PER_THREAD,
COL_MIN_PER_PARENT,
COL_MAX_PER_PARENT,
COL_AVERAGE_PER_PARENT,
COL_NCALLS_PER_PARENT,
COL_ACTIVE_TIME,
COL_ACTIVE_PERCENT,
COL_COLUMNS_NUMBER
};
//////////////////////////////////////////////////////////////////////////
class EasyTreeWidgetItem : public QTreeWidgetItem
{
typedef QTreeWidgetItem Parent;
typedef EasyTreeWidgetItem This;
const ::profiler::block_index_t m_block;
QRgb m_customBGColor;
QRgb m_customTextColor;
public:
using Parent::setBackgroundColor;
using Parent::setTextColor;
explicit EasyTreeWidgetItem(const ::profiler::block_index_t _treeBlock = ::profiler_gui::numeric_max<decltype(m_block)>(), Parent* _parent = nullptr);
virtual ~EasyTreeWidgetItem();
bool operator < (const Parent& _other) const override;
public:
::profiler::block_index_t block_index() const;
::profiler_gui::EasyBlock& guiBlock();
const ::profiler::BlocksTree& block() const;
::profiler::timestamp_t duration() const;
::profiler::timestamp_t selfDuration() const;
void setTimeSmart(int _column, ::profiler_gui::TimeUnits _units, const ::profiler::timestamp_t& _time, const QString& _prefix);
void setTimeSmart(int _column, ::profiler_gui::TimeUnits _units, const ::profiler::timestamp_t& _time);
void setTimeMs(int _column, const ::profiler::timestamp_t& _time);
void setTimeMs(int _column, const ::profiler::timestamp_t& _time, const QString& _prefix);
void setBackgroundColor(QRgb _color);
void setTextColor(QRgb _color);
void colorize(bool _colorize);
void collapseAll();
void expandAll();
}; // END of class EasyTreeWidgetItem.
//////////////////////////////////////////////////////////////////////////
#endif // EASY__TREE_WIDGET_ITEM__H_

View File

@ -0,0 +1,990 @@
/************************************************************************
* file name : tree_widget_loader.h
* ----------------- :
* creation time : 2016/08/18
* author : Victor Zarubkin
* email : v.s.zarubkin@gmail.com
* ----------------- :
* description : The file contains implementation of EasyTreeWidgetLoader which aim is
* : to load EasyProfiler blocks hierarchy in separate thread.
* ----------------- :
* change log : * 2016/08/18 Victor Zarubkin: moved sources from blocks_tree_widget.h/.cpp
* : and renamed Prof* to Easy*.
* :
* : *
* ----------------- :
* license : Lightweight profiler library for c++
* : Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
* :
* :
* : Licensed under the Apache License, Version 2.0 (the "License");
* : you may not use this file except in compliance with the License.
* : You may obtain a copy of the License at
* :
* : http://www.apache.org/licenses/LICENSE-2.0
* :
* : Unless required by applicable law or agreed to in writing, software
* : distributed under the License is distributed on an "AS IS" BASIS,
* : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* : See the License for the specific language governing permissions and
* : limitations under the License.
* :
* :
* : GNU General Public License Usage
* : Alternatively, this file may be used under the terms of the GNU
* : General Public License as published by the Free Software Foundation,
* : either version 3 of the License, or (at your option) any later version.
* :
* : This program is distributed in the hope that it will be useful,
* : but WITHOUT ANY WARRANTY; without even the implied warranty of
* : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
* : GNU General Public License for more details.
* :
* : You should have received a copy of the GNU General Public License
* : along with this program.If not, see <http://www.gnu.org/licenses/>.
************************************************************************/
#include "tree_widget_loader.h"
#include "tree_widget_item.h"
#include "globals.h"
#ifdef _WIN32
#include <Windows.h>
#include <processthreadsapi.h>
#endif
#ifdef max
#undef max
#endif
#ifdef min
#undef min
#endif
//////////////////////////////////////////////////////////////////////////
EasyTreeWidgetLoader::EasyTreeWidgetLoader()
: m_bDone(ATOMIC_VAR_INIT(false))
, m_bInterrupt(ATOMIC_VAR_INIT(false))
, m_progress(ATOMIC_VAR_INIT(0))
, m_mode(EasyTreeMode_Full)
{
}
EasyTreeWidgetLoader::~EasyTreeWidgetLoader()
{
interrupt(true);
}
bool EasyTreeWidgetLoader::done() const
{
return m_bDone.load();
}
void EasyTreeWidgetLoader::setDone()
{
m_bDone.store(true);
//m_progress.store(100);
}
void EasyTreeWidgetLoader::setProgress(int _progress)
{
m_progress.store(_progress);
}
bool EasyTreeWidgetLoader::interrupted() const
{
return m_bInterrupt.load();
}
int EasyTreeWidgetLoader::progress() const
{
return m_progress.load();
}
void EasyTreeWidgetLoader::takeTopLevelItems(ThreadedItems& _output)
{
if (done())
{
_output = ::std::move(m_topLevelItems);
m_topLevelItems.clear();
}
}
void EasyTreeWidgetLoader::takeItems(Items& _output)
{
if (done())
{
_output = ::std::move(m_items);
m_items.clear();
}
}
void EasyTreeWidgetLoader::interrupt(bool _wait)
{
m_bInterrupt.store(true);
if (m_thread.joinable())
m_thread.join();
m_bInterrupt.store(false);
m_bDone.store(false);
m_progress.store(0);
if (!_wait)
{
auto deleter_thread = ::std::thread([](decltype(m_topLevelItems) _items)
{
#ifdef _WIN32
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_LOWEST);
#endif
for (auto item : _items)
delete item.second;
}, ::std::move(m_topLevelItems));
deleter_thread.detach();
}
else
{
for (auto item : m_topLevelItems)
delete item.second;
}
m_items.clear();
m_topLevelItems.clear();
m_iditems.clear();
}
void EasyTreeWidgetLoader::fillTree(::profiler::timestamp_t& _beginTime, const unsigned int _blocksNumber, const ::profiler::thread_blocks_tree_t& _blocksTree, bool _colorizeRows, EasyTreeMode _mode)
{
interrupt();
m_mode = _mode;
m_thread = ::std::thread(&EasyTreeWidgetLoader::setTreeInternal1, this,
::std::ref(_beginTime), _blocksNumber, ::std::ref(_blocksTree), _colorizeRows,
EASY_GLOBALS.add_zero_blocks_to_hierarchy, EASY_GLOBALS.use_decorated_thread_name, EASY_GLOBALS.time_units);
}
void EasyTreeWidgetLoader::fillTreeBlocks(const::profiler_gui::TreeBlocks& _blocks, ::profiler::timestamp_t _beginTime, ::profiler::timestamp_t _left, ::profiler::timestamp_t _right, bool _strict, bool _colorizeRows, EasyTreeMode _mode)
{
interrupt();
m_mode = _mode;
m_thread = ::std::thread(&EasyTreeWidgetLoader::setTreeInternal2, this,
_beginTime, ::std::ref(_blocks), _left, _right, _strict, _colorizeRows,
EASY_GLOBALS.add_zero_blocks_to_hierarchy, EASY_GLOBALS.use_decorated_thread_name, EASY_GLOBALS.time_units);
}
//////////////////////////////////////////////////////////////////////////
void EasyTreeWidgetLoader::setTreeInternal1(::profiler::timestamp_t& _beginTime, const unsigned int _blocksNumber, const ::profiler::thread_blocks_tree_t& _blocksTree, bool _colorizeRows, bool _addZeroBlocks, bool _decoratedThreadNames, ::profiler_gui::TimeUnits _units)
{
m_items.reserve(_blocksNumber + _blocksTree.size()); // _blocksNumber does not include Thread root blocks
::profiler::timestamp_t finishtime = 0;
for (const auto& threadTree : _blocksTree)
{
const auto node_block = blocksTree(threadTree.second.children.front()).node;
const auto startTime = node_block->begin();
const auto endTime = node_block->end();
if (_beginTime > startTime)
_beginTime = startTime;
if (finishtime < endTime)
finishtime = endTime;
}
//const QSignalBlocker b(this);
const auto u_thread = ::profiler_gui::toUnicode("thread");
int i = 0;
const int total = static_cast<int>(_blocksTree.size());
for (const auto& threadTree : _blocksTree)
{
if (interrupted())
break;
const auto& root = threadTree.second;
auto item = new EasyTreeWidgetItem();
item->setText(COL_NAME, ::profiler_gui::decoratedThreadName(_decoratedThreadNames, root, u_thread));
::profiler::timestamp_t duration = 0;
if (!root.children.empty())
duration = blocksTree(root.children.back()).node->end() - blocksTree(root.children.front()).node->begin();
item->setTimeSmart(COL_DURATION, _units, duration);
item->setBackgroundColor(::profiler_gui::SELECTED_THREAD_BACKGROUND);
item->setTextColor(::profiler_gui::SELECTED_THREAD_FOREGROUND);
//_items.push_back(item);
item->setTimeSmart(COL_SELF_DURATION, _units, root.profiled_time);
::profiler::timestamp_t children_duration = 0;
const auto children_items_number = setTreeInternal(root, 0, _beginTime, root.children, item, nullptr, _beginTime, finishtime + 1000000000ULL, false, children_duration, _colorizeRows, _addZeroBlocks, _units);
if (children_items_number > 0)
{
//total_items += children_items_number + 1;
//addTopLevelItem(item);
//m_roots[threadTree.first] = item;
m_topLevelItems.emplace_back(root.thread_id, item);
}
else
{
//_items.pop_back();
delete item;
}
setProgress((100 * ++i) / total);
}
setDone();
//return total_items;
}
//////////////////////////////////////////////////////////////////////////
// auto calculateTotalChildrenNumber(const ::profiler::BlocksTree& _tree) -> decltype(_tree.children.size())
// {
// auto children_number = _tree.children.size();
// for (auto i : _tree.children)
// children_number += calculateTotalChildrenNumber(blocksTree(i));
// return children_number;
// }
typedef ::std::unordered_map<::profiler::thread_id_t, ::profiler::block_index_t, ::profiler_gui::do_no_hash<::profiler::thread_id_t>::hasher_t> BeginEndIndicesMap;
void EasyTreeWidgetLoader::setTreeInternal2(const ::profiler::timestamp_t& _beginTime, const ::profiler_gui::TreeBlocks& _blocks, ::profiler::timestamp_t _left, ::profiler::timestamp_t _right, bool _strict, bool _colorizeRows, bool _addZeroBlocks, bool _decoratedThreadNames, ::profiler_gui::TimeUnits _units)
{
//size_t blocksNumber = 0;
//for (const auto& block : _blocks)
// blocksNumber += calculateTotalChildrenNumber(*block.tree);
// //blocksNumber += block.tree->total_children_number;
//m_items.reserve(blocksNumber + _blocks.size()); // blocksNumber does not include root blocks
BeginEndIndicesMap beginEndMap;
RootsMap threadsMap;
auto const setTree = (m_mode == EasyTreeMode_Full) ? &EasyTreeWidgetLoader::setTreeInternal : &EasyTreeWidgetLoader::setTreeInternalPlain;
const auto u_thread = ::profiler_gui::toUnicode("thread");
int i = 0, total = static_cast<int>(_blocks.size());
//const QSignalBlocker b(this);
for (const auto& block : _blocks)
{
if (interrupted())
break;
auto& gui_block = easyBlock(block.tree);
const auto startTime = gui_block.tree.node->begin();
const auto endTime = gui_block.tree.node->end();
if (startTime > _right || endTime < _left)
{
setProgress((90 * ++i) / total);
continue;
}
::profiler::timestamp_t duration = 0;
EasyTreeWidgetItem* thread_item = nullptr;
::profiler::block_index_t& firstCswitch = beginEndMap[block.root->thread_id];
auto thread_item_it = threadsMap.find(block.root->thread_id);
if (thread_item_it != threadsMap.end())
{
thread_item = thread_item_it->second;
}
else
{
thread_item = new EasyTreeWidgetItem();
thread_item->setText(COL_NAME, ::profiler_gui::decoratedThreadName(_decoratedThreadNames, *block.root, u_thread));
if (!block.root->children.empty())
duration = blocksTree(block.root->children.back()).node->end() - blocksTree(block.root->children.front()).node->begin();
thread_item->setTimeSmart(COL_DURATION, _units, duration);
thread_item->setBackgroundColor(::profiler_gui::SELECTED_THREAD_BACKGROUND);
thread_item->setTextColor(::profiler_gui::SELECTED_THREAD_FOREGROUND);
// Sum of all children durations:
thread_item->setTimeSmart(COL_SELF_DURATION, _units, block.root->profiled_time);
threadsMap.insert(::std::make_pair(block.root->thread_id, thread_item));
firstCswitch = 0;
auto it = ::std::lower_bound(block.root->sync.begin(), block.root->sync.end(), _left, [](::profiler::block_index_t ind, decltype(_left) _val)
{
return EASY_GLOBALS.gui_blocks[ind].tree.node->begin() < _val;
});
if (it != block.root->sync.end())
{
firstCswitch = it - block.root->sync.begin();
if (firstCswitch > 0)
--firstCswitch;
}
else
{
firstCswitch = static_cast<::profiler::block_index_t>(block.root->sync.size());
}
}
bool hasContextSwitch = false;
::profiler::timestamp_t idleTime = 0;
for (::profiler::block_index_t ind = firstCswitch, ncs = static_cast<::profiler::block_index_t>(block.root->sync.size()); ind < ncs; ++ind)
{
auto cs_index = block.root->sync[ind];
const auto cs = EASY_GLOBALS.gui_blocks[cs_index].tree.node;
if (cs->begin() > endTime)
{
if (!hasContextSwitch)
firstCswitch = ind;
break;
}
if (startTime <= cs->begin() && cs->end() <= endTime)
{
if (!hasContextSwitch)
{
firstCswitch = ind;
hasContextSwitch = true;
}
idleTime += cs->duration();
}
}
auto item = new EasyTreeWidgetItem(block.tree, thread_item);
duration = endTime - startTime;
auto name = *gui_block.tree.node->name() != 0 ? gui_block.tree.node->name() : easyDescriptor(gui_block.tree.node->id()).name();
item->setText(COL_NAME, ::profiler_gui::toUnicode(name));
item->setTimeSmart(COL_DURATION, _units, duration);
auto active_time = duration - idleTime;
auto active_percent = duration == 0 ? 100. : ::profiler_gui::percentReal(active_time, duration);
item->setTimeSmart(COL_ACTIVE_TIME, _units, active_time);
item->setText(COL_ACTIVE_PERCENT, QString::number(active_percent, 'g', 3));
item->setData(COL_ACTIVE_PERCENT, Qt::UserRole, active_percent);
item->setTimeMs(COL_BEGIN, startTime - _beginTime);
item->setTimeMs(COL_END, endTime - _beginTime);
item->setData(COL_PERCENT_PER_FRAME, Qt::UserRole, 0);
auto percentage_per_thread = ::profiler_gui::percent(duration, block.root->profiled_time);
item->setData(COL_PERCENT_PER_PARENT, Qt::UserRole, percentage_per_thread);
item->setText(COL_PERCENT_PER_PARENT, QString::number(percentage_per_thread));
if (gui_block.tree.per_thread_stats != nullptr) // if there is per_thread_stats then there are other stats also
{
const ::profiler::BlockStatistics* per_thread_stats = gui_block.tree.per_thread_stats;
const ::profiler::BlockStatistics* per_parent_stats = gui_block.tree.per_parent_stats;
const ::profiler::BlockStatistics* per_frame_stats = gui_block.tree.per_frame_stats;
if (per_thread_stats->calls_number > 1 || !EASY_GLOBALS.display_only_relevant_stats)
{
item->setTimeSmart(COL_MIN_PER_THREAD, _units, easyBlock(per_thread_stats->min_duration_block).tree.node->duration(), "min ");
item->setTimeSmart(COL_MAX_PER_THREAD, _units, easyBlock(per_thread_stats->max_duration_block).tree.node->duration(), "max ");
item->setTimeSmart(COL_AVERAGE_PER_THREAD, _units, per_thread_stats->average_duration());
item->setTimeSmart(COL_DURATION_SUM_PER_THREAD, _units, per_thread_stats->total_duration);
}
item->setData(COL_NCALLS_PER_THREAD, Qt::UserRole, per_thread_stats->calls_number);
item->setText(COL_NCALLS_PER_THREAD, QString::number(per_thread_stats->calls_number));
percentage_per_thread = ::profiler_gui::percent(per_thread_stats->total_duration, block.root->profiled_time);
item->setData(COL_PERCENT_SUM_PER_THREAD, Qt::UserRole, percentage_per_thread);
item->setText(COL_PERCENT_SUM_PER_THREAD, QString::number(percentage_per_thread));
if (per_parent_stats->calls_number > 1 || !EASY_GLOBALS.display_only_relevant_stats)
{
item->setTimeSmart(COL_MIN_PER_PARENT, _units, easyBlock(per_parent_stats->min_duration_block).tree.node->duration(), "min ");
item->setTimeSmart(COL_MAX_PER_PARENT, _units, easyBlock(per_parent_stats->max_duration_block).tree.node->duration(), "max ");
item->setTimeSmart(COL_AVERAGE_PER_PARENT, _units, per_parent_stats->average_duration());
item->setTimeSmart(COL_DURATION_SUM_PER_PARENT, _units, per_parent_stats->total_duration);
}
item->setData(COL_NCALLS_PER_PARENT, Qt::UserRole, per_parent_stats->calls_number);
item->setText(COL_NCALLS_PER_PARENT, QString::number(per_parent_stats->calls_number));
if (per_frame_stats->calls_number > 1 || !EASY_GLOBALS.display_only_relevant_stats)
{
item->setTimeSmart(COL_MIN_PER_FRAME, _units, easyBlock(per_frame_stats->min_duration_block).tree.node->duration(), "min ");
item->setTimeSmart(COL_MAX_PER_FRAME, _units, easyBlock(per_frame_stats->max_duration_block).tree.node->duration(), "max ");
item->setTimeSmart(COL_AVERAGE_PER_FRAME, _units, per_frame_stats->average_duration());
item->setTimeSmart(COL_DURATION_SUM_PER_FRAME, _units, per_frame_stats->total_duration);
}
item->setData(COL_NCALLS_PER_FRAME, Qt::UserRole, per_frame_stats->calls_number);
item->setText(COL_NCALLS_PER_FRAME, QString::number(per_frame_stats->calls_number));
}
else
{
item->setData(COL_PERCENT_SUM_PER_THREAD, Qt::UserRole, 0);
item->setText(COL_PERCENT_SUM_PER_THREAD, "");
}
const auto color = easyDescriptor(gui_block.tree.node->id()).color();
//const auto bgColor = ::profiler_gui::fromProfilerRgb(::profiler::colors::get_red(color), ::profiler::colors::get_green(color), ::profiler::colors::get_blue(color));
const auto fgColor = ::profiler_gui::textColorForRgb(color);//0x00ffffff - bgColor;
item->setBackgroundColor(color);
item->setTextColor(fgColor);
#ifdef EASY_TREE_WIDGET__USE_VECTOR
auto item_index = static_cast<unsigned int>(m_items.size());
m_items.push_back(item);
#endif
size_t children_items_number = 0;
::profiler::timestamp_t children_duration = 0;
if (!gui_block.tree.children.empty())
{
m_iditems.clear();
children_items_number = (this->*setTree)(*block.root, firstCswitch, _beginTime, gui_block.tree.children, item, item, _left, _right, _strict, children_duration, _colorizeRows, _addZeroBlocks, _units);
if (interrupted())
break;
}
int percentage = 100;
auto self_duration = duration - children_duration;
if (children_duration > 0 && duration > 0)
{
percentage = static_cast<int>(0.5 + 100. * static_cast<double>(self_duration) / static_cast<double>(duration));
}
item->setTimeSmart(COL_SELF_DURATION, _units, self_duration);
item->setData(COL_SELF_DURATION_PERCENT, Qt::UserRole, percentage);
item->setText(COL_SELF_DURATION_PERCENT, QString::number(percentage));
if (children_items_number > 0 || !_strict || (startTime >= _left && endTime <= _right))
{
//total_items += children_items_number + 1;
#ifdef EASY_TREE_WIDGET__USE_VECTOR
gui_block.tree_item = item_index;
#endif
if (_colorizeRows)
item->colorize(_colorizeRows);
if (gui_block.expanded)
item->setExpanded(true);
#ifndef EASY_TREE_WIDGET__USE_VECTOR
m_items.insert(::std::make_pair(block.tree, item));
#endif
}
else
{
#ifdef EASY_TREE_WIDGET__USE_VECTOR
m_items.pop_back();
#endif
delete item;
}
setProgress((90 * ++i) / total);
}
i = 0;
total = static_cast<int>(threadsMap.size());
for (auto& it : threadsMap)
{
auto item = it.second;
if (item->childCount() > 0)
{
//addTopLevelItem(item);
//m_roots[it.first] = item;
//_items.push_back(item);
m_topLevelItems.emplace_back(it.first, item);
//++total_items;
}
else
{
delete item;
}
setProgress(90 + (10 * ++i) / total);
}
setDone();
//return total_items;
}
//////////////////////////////////////////////////////////////////////////
size_t EasyTreeWidgetLoader::setTreeInternal(const ::profiler::BlocksTreeRoot& _threadRoot, ::profiler::block_index_t _firstCswitch, const ::profiler::timestamp_t& _beginTime, const ::profiler::BlocksTree::children_t& _children, EasyTreeWidgetItem* _parent, EasyTreeWidgetItem* _frame, ::profiler::timestamp_t _left, ::profiler::timestamp_t _right, bool _strict, ::profiler::timestamp_t& _duration, bool _colorizeRows, bool _addZeroBlocks, ::profiler_gui::TimeUnits _units)
{
auto const setTree = m_mode == EasyTreeMode_Full ? &EasyTreeWidgetLoader::setTreeInternal : &EasyTreeWidgetLoader::setTreeInternalPlain;
size_t total_items = 0;
for (auto child_index : _children)
{
if (interrupted())
break;
auto& gui_block = easyBlock(child_index);
const auto& child = gui_block.tree;
const auto startTime = child.node->begin();
const auto endTime = child.node->end();
const auto duration = endTime - startTime;
if (duration == 0 && !_addZeroBlocks)
continue;
_duration += duration;
if (startTime > _right || endTime < _left)
continue;
bool hasContextSwitch = false;
::profiler::timestamp_t idleTime = 0;
for (::profiler::block_index_t ind = _firstCswitch, ncs = static_cast<::profiler::block_index_t>(_threadRoot.sync.size()); ind < ncs; ++ind)
{
auto cs_index = _threadRoot.sync[ind];
const auto cs = EASY_GLOBALS.gui_blocks[cs_index].tree.node;
if (cs->begin() > endTime)
{
if (!hasContextSwitch)
_firstCswitch = ind;
break;
}
if (startTime <= cs->begin() && cs->end() <= endTime)
{
if (!hasContextSwitch)
{
_firstCswitch = ind;
hasContextSwitch = true;
}
idleTime += cs->duration();
}
}
auto item = new EasyTreeWidgetItem(child_index, _parent);
auto name = *child.node->name() != 0 ? child.node->name() : easyDescriptor(child.node->id()).name();
item->setText(COL_NAME, ::profiler_gui::toUnicode(name));
item->setTimeSmart(COL_DURATION, _units, duration);
auto active_time = duration - idleTime;
auto active_percent = duration == 0 ? 100. : ::profiler_gui::percentReal(active_time, duration);
item->setTimeSmart(COL_ACTIVE_TIME, _units, active_time);
item->setText(COL_ACTIVE_PERCENT, QString::number(active_percent, 'g', 3));
item->setData(COL_ACTIVE_PERCENT, Qt::UserRole, active_percent);
item->setTimeMs(COL_BEGIN, startTime - _beginTime);
item->setTimeMs(COL_END, endTime - _beginTime);
item->setData(COL_PERCENT_SUM_PER_THREAD, Qt::UserRole, 0);
if (child.per_thread_stats != nullptr) // if there is per_thread_stats then there are other stats also
{
const ::profiler::BlockStatistics* per_thread_stats = child.per_thread_stats;
const ::profiler::BlockStatistics* per_parent_stats = child.per_parent_stats;
const ::profiler::BlockStatistics* per_frame_stats = child.per_frame_stats;
auto parent_duration = _parent->duration();
auto percentage = duration == 0 ? 0 : ::profiler_gui::percent(duration, parent_duration);
auto percentage_sum = ::profiler_gui::percent(per_parent_stats->total_duration, parent_duration);
item->setData(COL_PERCENT_PER_PARENT, Qt::UserRole, percentage);
item->setText(COL_PERCENT_PER_PARENT, QString::number(percentage));
item->setData(COL_PERCENT_SUM_PER_PARENT, Qt::UserRole, percentage_sum);
item->setText(COL_PERCENT_SUM_PER_PARENT, QString::number(percentage_sum));
if (_frame != nullptr)
{
if (_parent != _frame)
{
parent_duration = _frame->duration();
percentage = duration == 0 ? 0 : ::profiler_gui::percent(duration, parent_duration);
percentage_sum = ::profiler_gui::percent(per_frame_stats->total_duration, parent_duration);
}
item->setData(COL_PERCENT_PER_FRAME, Qt::UserRole, percentage);
item->setText(COL_PERCENT_PER_FRAME, QString::number(percentage));
item->setData(COL_PERCENT_SUM_PER_FRAME, Qt::UserRole, percentage_sum);
item->setText(COL_PERCENT_SUM_PER_FRAME, QString::number(percentage_sum));
}
else
{
item->setData(COL_PERCENT_PER_FRAME, Qt::UserRole, 0);
item->setData(COL_PERCENT_SUM_PER_FRAME, Qt::UserRole, 0);
auto percentage_per_thread = ::profiler_gui::percent(duration, _threadRoot.profiled_time);
item->setData(COL_PERCENT_PER_PARENT, Qt::UserRole, percentage_per_thread);
item->setText(COL_PERCENT_PER_PARENT, QString::number(percentage_per_thread));
}
if (per_thread_stats->calls_number > 1 || !EASY_GLOBALS.display_only_relevant_stats)
{
item->setTimeSmart(COL_MIN_PER_THREAD, _units, easyBlock(per_thread_stats->min_duration_block).tree.node->duration(), "min ");
item->setTimeSmart(COL_MAX_PER_THREAD, _units, easyBlock(per_thread_stats->max_duration_block).tree.node->duration(), "max ");
item->setTimeSmart(COL_AVERAGE_PER_THREAD, _units, per_thread_stats->average_duration());
item->setTimeSmart(COL_DURATION_SUM_PER_THREAD, _units, per_thread_stats->total_duration);
}
item->setData(COL_NCALLS_PER_THREAD, Qt::UserRole, per_thread_stats->calls_number);
item->setText(COL_NCALLS_PER_THREAD, QString::number(per_thread_stats->calls_number));
auto percentage_per_thread = ::profiler_gui::percent(per_thread_stats->total_duration, _threadRoot.profiled_time);
item->setData(COL_PERCENT_SUM_PER_THREAD, Qt::UserRole, percentage_per_thread);
item->setText(COL_PERCENT_SUM_PER_THREAD, QString::number(percentage_per_thread));
if (per_parent_stats->calls_number > 1 || !EASY_GLOBALS.display_only_relevant_stats)
{
item->setTimeSmart(COL_MIN_PER_PARENT, _units, easyBlock(per_parent_stats->min_duration_block).tree.node->duration(), "min ");
item->setTimeSmart(COL_MAX_PER_PARENT, _units, easyBlock(per_parent_stats->max_duration_block).tree.node->duration(), "max ");
item->setTimeSmart(COL_AVERAGE_PER_PARENT, _units, per_parent_stats->average_duration());
item->setTimeSmart(COL_DURATION_SUM_PER_PARENT, _units, per_parent_stats->total_duration);
}
item->setData(COL_NCALLS_PER_PARENT, Qt::UserRole, per_parent_stats->calls_number);
item->setText(COL_NCALLS_PER_PARENT, QString::number(per_parent_stats->calls_number));
if (per_frame_stats->calls_number > 1 || !EASY_GLOBALS.display_only_relevant_stats)
{
item->setTimeSmart(COL_MIN_PER_FRAME, _units, easyBlock(per_frame_stats->min_duration_block).tree.node->duration(), "min ");
item->setTimeSmart(COL_MAX_PER_FRAME, _units, easyBlock(per_frame_stats->max_duration_block).tree.node->duration(), "max ");
item->setTimeSmart(COL_AVERAGE_PER_FRAME, _units, per_frame_stats->average_duration());
item->setTimeSmart(COL_DURATION_SUM_PER_FRAME, _units, per_frame_stats->total_duration);
}
item->setData(COL_NCALLS_PER_FRAME, Qt::UserRole, per_frame_stats->calls_number);
item->setText(COL_NCALLS_PER_FRAME, QString::number(per_frame_stats->calls_number));
}
else
{
if (_frame == nullptr)
{
auto percentage_per_thread = ::profiler_gui::percent(duration, _threadRoot.profiled_time);
item->setData(COL_PERCENT_PER_PARENT, Qt::UserRole, percentage_per_thread);
item->setText(COL_PERCENT_PER_PARENT, QString::number(percentage_per_thread));
}
else
{
item->setData(COL_PERCENT_PER_PARENT, Qt::UserRole, 0);
}
item->setData(COL_PERCENT_SUM_PER_PARENT, Qt::UserRole, 0);
item->setData(COL_PERCENT_SUM_PER_THREAD, Qt::UserRole, 0);
}
const auto color = easyDescriptor(child.node->id()).color();
//const auto bgColor = ::profiler_gui::fromProfilerRgb(::profiler::colors::get_red(color), ::profiler::colors::get_green(color), ::profiler::colors::get_blue(color));
const auto fgColor = ::profiler_gui::textColorForRgb(color);// 0x00ffffff - bgColor;
item->setBackgroundColor(color);
item->setTextColor(fgColor);
#ifdef EASY_TREE_WIDGET__USE_VECTOR
auto item_index = static_cast<uint32_t>(m_items.size());
m_items.push_back(item);
#endif
size_t children_items_number = 0;
::profiler::timestamp_t children_duration = 0;
if (!child.children.empty())
{
m_iditems.clear();
children_items_number = (this->*setTree)(_threadRoot, _firstCswitch, _beginTime, child.children, item, _frame ? _frame : item, _left, _right, _strict, children_duration, _colorizeRows, _addZeroBlocks, _units);
if (interrupted())
break;
}
int percentage = 100;
auto self_duration = duration - children_duration;
if (children_duration > 0 && duration > 0)
{
percentage = ::profiler_gui::percent(self_duration, duration);
}
item->setTimeSmart(COL_SELF_DURATION, _units, self_duration);
item->setData(COL_SELF_DURATION_PERCENT, Qt::UserRole, percentage);
item->setText(COL_SELF_DURATION_PERCENT, QString::number(percentage));
if (children_items_number > 0 || !_strict || (startTime >= _left && endTime <= _right))
{
total_items += children_items_number + 1;
#ifdef EASY_TREE_WIDGET__USE_VECTOR
gui_block.tree_item = item_index;
#endif
if (_colorizeRows)
item->colorize(_colorizeRows);
if (gui_block.expanded)
item->setExpanded(true);
#ifndef EASY_TREE_WIDGET__USE_VECTOR
m_items.insert(::std::make_pair(child_index, item));
#endif
}
else
{
#ifdef EASY_TREE_WIDGET__USE_VECTOR
m_items.pop_back();
#endif
delete item;
}
}
return total_items;
}
//////////////////////////////////////////////////////////////////////////
::profiler::timestamp_t EasyTreeWidgetLoader::calculateChildrenDurationRecursive(const ::profiler::BlocksTree::children_t& _children, ::profiler::block_id_t _id)
{
::profiler::timestamp_t total_duration = 0;
for (auto child_index : _children)
{
if (interrupted())
break;
const auto& gui_block = easyBlock(child_index);
total_duration += gui_block.tree.node->duration();
if (gui_block.tree.node->id() == _id)
total_duration += calculateChildrenDurationRecursive(gui_block.tree.children, _id);
}
return total_duration;
}
size_t EasyTreeWidgetLoader::setTreeInternalPlain(const ::profiler::BlocksTreeRoot& _threadRoot, ::profiler::block_index_t _firstCswitch, const ::profiler::timestamp_t& _beginTime, const ::profiler::BlocksTree::children_t& _children, EasyTreeWidgetItem*, EasyTreeWidgetItem* _frame, ::profiler::timestamp_t _left, ::profiler::timestamp_t _right, bool _strict, ::profiler::timestamp_t& _duration, bool _colorizeRows, bool _addZeroBlocks, ::profiler_gui::TimeUnits _units)
{
size_t total_items = 0;
for (auto child_index : _children)
{
if (interrupted())
break;
const auto& gui_block = easyBlock(child_index);
const auto& child = gui_block.tree;
const auto startTime = child.node->begin();
const auto endTime = child.node->end();
const auto duration = endTime - startTime;
_duration += duration;
auto it = m_iditems.find(child.node->id());
if (it != m_iditems.end())
{
++total_items;
size_t children_items_number = 0;
::profiler::timestamp_t children_duration = 0;
if (!child.children.empty())
{
children_items_number = setTreeInternalPlain(_threadRoot, _firstCswitch, _beginTime, child.children, _frame, _frame, _left, _right, _strict, children_duration, _colorizeRows, _addZeroBlocks, _units);
if (interrupted())
break;
}
if (it->second != nullptr && child.per_frame_stats != nullptr)
{
auto item = it->second;
//auto children_duration = calculateChildrenDurationRecursive(child.children, it->first);
if (children_duration != 0)
{
auto self_duration = item->data(COL_SELF_DURATION, Qt::UserRole).toULongLong() - children_duration;
int percentage = 100;
if (child.per_frame_stats->total_duration > 0)
percentage = ::profiler_gui::percent(self_duration, child.per_frame_stats->total_duration);
item->setTimeSmart(COL_SELF_DURATION, _units, self_duration);
item->setData(COL_SELF_DURATION_PERCENT, Qt::UserRole, percentage);
item->setText(COL_SELF_DURATION_PERCENT, QString::number(percentage));
}
bool hasContextSwitch = false;
::profiler::timestamp_t idleTime = 0;
for (::profiler::block_index_t ind = _firstCswitch, ncs = static_cast<::profiler::block_index_t>(_threadRoot.sync.size()); ind < ncs; ++ind)
{
auto cs_index = _threadRoot.sync[ind];
const auto cs = EASY_GLOBALS.gui_blocks[cs_index].tree.node;
if (cs->begin() > endTime)
{
if (!hasContextSwitch)
_firstCswitch = ind;
break;
}
if (startTime <= cs->begin() && cs->end() <= endTime)
{
if (!hasContextSwitch)
{
_firstCswitch = ind;
hasContextSwitch = true;
}
idleTime += cs->duration();
}
}
auto active_time = item->data(COL_ACTIVE_TIME, Qt::UserRole).toULongLong() - idleTime;
auto active_percent = child.per_frame_stats->total_duration == 0 ? 100. : ::profiler_gui::percentReal(active_time, child.per_frame_stats->total_duration);
item->setTimeSmart(COL_ACTIVE_TIME, _units, active_time);
item->setText(COL_ACTIVE_PERCENT, QString::number(active_percent, 'g', 3));
item->setData(COL_ACTIVE_PERCENT, Qt::UserRole, active_percent);
}
continue;
}
if (startTime > _right || endTime < _left)
continue;
bool hasContextSwitch = false;
::profiler::timestamp_t idleTime = 0;
for (::profiler::block_index_t ind = _firstCswitch, ncs = static_cast<::profiler::block_index_t>(_threadRoot.sync.size()); ind < ncs; ++ind)
{
auto cs_index = _threadRoot.sync[ind];
const auto cs = EASY_GLOBALS.gui_blocks[cs_index].tree.node;
if (cs->begin() > endTime)
{
if (!hasContextSwitch)
_firstCswitch = ind;
break;
}
if (startTime <= cs->begin() && cs->end() <= endTime)
{
if (!hasContextSwitch)
{
_firstCswitch = ind;
hasContextSwitch = true;
}
idleTime += cs->duration();
}
}
auto item = new EasyTreeWidgetItem(child_index, _frame);
auto name = *child.node->name() != 0 ? child.node->name() : easyDescriptor(child.node->id()).name();
item->setText(COL_NAME, ::profiler_gui::toUnicode(name));
if (child.per_thread_stats != nullptr) // if there is per_thread_stats then there are other stats also
{
const ::profiler::BlockStatistics* per_thread_stats = child.per_thread_stats;
if (per_thread_stats->calls_number > 1 || !EASY_GLOBALS.display_only_relevant_stats)
{
item->setTimeSmart(COL_MIN_PER_THREAD, _units, easyBlock(per_thread_stats->min_duration_block).tree.node->duration(), "min ");
item->setTimeSmart(COL_MAX_PER_THREAD, _units, easyBlock(per_thread_stats->max_duration_block).tree.node->duration(), "max ");
item->setTimeSmart(COL_AVERAGE_PER_THREAD, _units, per_thread_stats->average_duration());
}
item->setTimeSmart(COL_DURATION_SUM_PER_THREAD, _units, per_thread_stats->total_duration);
item->setData(COL_NCALLS_PER_THREAD, Qt::UserRole, per_thread_stats->calls_number);
item->setText(COL_NCALLS_PER_THREAD, QString::number(per_thread_stats->calls_number));
auto percentage_per_thread = ::profiler_gui::percent(per_thread_stats->total_duration, _threadRoot.profiled_time);
item->setData(COL_PERCENT_SUM_PER_THREAD, Qt::UserRole, percentage_per_thread);
item->setText(COL_PERCENT_SUM_PER_THREAD, QString::number(percentage_per_thread));
const ::profiler::BlockStatistics* per_frame_stats = child.per_frame_stats;
const auto percentage_sum = ::profiler_gui::percent(per_frame_stats->total_duration, _frame->duration());
item->setData(COL_PERCENT_PER_FRAME, Qt::UserRole, percentage_sum);
item->setText(COL_PERCENT_PER_FRAME, QString::number(percentage_sum));
if (per_frame_stats->calls_number > 1 || !EASY_GLOBALS.display_only_relevant_stats)
{
item->setTimeSmart(COL_MIN_PER_FRAME, _units, easyBlock(per_frame_stats->min_duration_block).tree.node->duration(), "min ");
item->setTimeSmart(COL_MAX_PER_FRAME, _units, easyBlock(per_frame_stats->max_duration_block).tree.node->duration(), "max ");
item->setTimeSmart(COL_AVERAGE_PER_FRAME, _units, per_frame_stats->average_duration());
}
item->setTimeSmart(COL_DURATION, _units, per_frame_stats->total_duration);
item->setData(COL_NCALLS_PER_FRAME, Qt::UserRole, per_frame_stats->calls_number);
item->setText(COL_NCALLS_PER_FRAME, QString::number(per_frame_stats->calls_number));
}
else
{
item->setData(COL_PERCENT_SUM_PER_THREAD, Qt::UserRole, 0);
item->setData(COL_PERCENT_PER_FRAME, Qt::UserRole, 0);
}
const auto color = easyDescriptor(child.node->id()).color();
const auto fgColor = ::profiler_gui::textColorForRgb(color);// 0x00ffffff - bgColor;
item->setBackgroundColor(color);
item->setTextColor(fgColor);
#ifdef EASY_TREE_WIDGET__USE_VECTOR
auto item_index = static_cast<uint32_t>(m_items.size());
m_items.push_back(item);
#endif
m_iditems[child.node->id()] = nullptr;
size_t children_items_number = 0;
::profiler::timestamp_t children_duration = 0;
if (!child.children.empty())
{
children_items_number = setTreeInternalPlain(_threadRoot, _firstCswitch, _beginTime, child.children, _frame, _frame, _left, _right, _strict, children_duration, _colorizeRows, _addZeroBlocks, _units);
if (interrupted())
break;
}
m_iditems[child.node->id()] = item;
if (child.per_frame_stats != nullptr)
{
int percentage = 100;
auto self_duration = child.per_frame_stats->total_duration - children_duration;
if (child.per_frame_stats->total_duration > 0)
percentage = ::profiler_gui::percent(self_duration, child.per_frame_stats->total_duration);
item->setTimeSmart(COL_SELF_DURATION, _units, self_duration);
item->setData(COL_SELF_DURATION_PERCENT, Qt::UserRole, percentage);
item->setText(COL_SELF_DURATION_PERCENT, QString::number(percentage));
auto active_time = child.per_frame_stats->total_duration - idleTime;
auto active_percent = child.per_frame_stats->total_duration == 0 ? 100. : ::profiler_gui::percentReal(active_time, child.per_frame_stats->total_duration);
item->setTimeSmart(COL_ACTIVE_TIME, _units, active_time);
item->setText(COL_ACTIVE_PERCENT, QString::number(active_percent, 'g', 3));
item->setData(COL_ACTIVE_PERCENT, Qt::UserRole, active_percent);
}
if (children_items_number > 0 || !_strict || (startTime >= _left && endTime <= _right))
{
total_items += children_items_number + 1;
#ifdef EASY_TREE_WIDGET__USE_VECTOR
gui_block.tree_item = item_index;
#endif
if (_colorizeRows)
item->colorize(_colorizeRows);
if (gui_block.expanded)
item->setExpanded(true);
#ifndef EASY_TREE_WIDGET__USE_VECTOR
m_items.insert(::std::make_pair(child_index, item));
#endif
}
else
{
#ifdef EASY_TREE_WIDGET__USE_VECTOR
m_items.pop_back();
#endif
delete item;
m_iditems.erase(gui_block.tree.node->id());
}
}
return total_items;
}
//////////////////////////////////////////////////////////////////////////

View File

@ -0,0 +1,125 @@
/************************************************************************
* file name : tree_widget_loader.h
* ----------------- :
* creation time : 2016/08/18
* author : Victor Zarubkin
* email : v.s.zarubkin@gmail.com
* ----------------- :
* description : The file contains declaration of EasyTreeWidgetLoader which aim is
* : to load EasyProfiler blocks hierarchy in separate thread.
* ----------------- :
* change log : * 2016/08/18 Victor Zarubkin: moved sources from blocks_tree_widget.h/.cpp
* : and renamed Prof* to Easy*.
* :
* : *
* ----------------- :
* license : Lightweight profiler library for c++
* : Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
* :
* :
* : Licensed under the Apache License, Version 2.0 (the "License");
* : you may not use this file except in compliance with the License.
* : You may obtain a copy of the License at
* :
* : http://www.apache.org/licenses/LICENSE-2.0
* :
* : Unless required by applicable law or agreed to in writing, software
* : distributed under the License is distributed on an "AS IS" BASIS,
* : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* : See the License for the specific language governing permissions and
* : limitations under the License.
* :
* :
* : GNU General Public License Usage
* : Alternatively, this file may be used under the terms of the GNU
* : General Public License as published by the Free Software Foundation,
* : either version 3 of the License, or (at your option) any later version.
* :
* : This program is distributed in the hope that it will be useful,
* : but WITHOUT ANY WARRANTY; without even the implied warranty of
* : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
* : GNU General Public License for more details.
* :
* : You should have received a copy of the GNU General Public License
* : along with this program.If not, see <http://www.gnu.org/licenses/>.
************************************************************************/
#ifndef EASY__TREE_WIDGET_LOADER__H_
#define EASY__TREE_WIDGET_LOADER__H_
#include <stdlib.h>
#include <vector>
//#include <unordered_set>
#include <thread>
#include <atomic>
#include "easy/reader.h"
#include "common_types.h"
//////////////////////////////////////////////////////////////////////////
class EasyTreeWidgetItem;
#ifndef EASY_TREE_WIDGET__USE_VECTOR
typedef ::std::unordered_map<::profiler::block_index_t, EasyTreeWidgetItem*, ::profiler_gui::do_no_hash<::profiler::block_index_t>::hasher_t> Items;
#else
typedef ::std::vector<EasyTreeWidgetItem*> Items;
#endif
typedef ::std::vector<::std::pair<::profiler::thread_id_t, EasyTreeWidgetItem*> > ThreadedItems;
typedef ::std::unordered_map<::profiler::thread_id_t, EasyTreeWidgetItem*, ::profiler_gui::do_no_hash<::profiler::thread_id_t>::hasher_t> RootsMap;
typedef ::std::unordered_map<::profiler::block_id_t, EasyTreeWidgetItem*, ::profiler_gui::do_no_hash<::profiler::block_index_t>::hasher_t> IdItems;
//////////////////////////////////////////////////////////////////////////
enum EasyTreeMode : uint8_t
{
EasyTreeMode_Full,
EasyTreeMode_Plain
};
//////////////////////////////////////////////////////////////////////////
class EasyTreeWidgetLoader Q_DECL_FINAL
{
ThreadedItems m_topLevelItems; ///<
Items m_items; ///<
IdItems m_iditems; ///<
::std::thread m_thread; ///<
::std::atomic_bool m_bDone; ///<
::std::atomic_bool m_bInterrupt; ///<
::std::atomic<int> m_progress; ///<
EasyTreeMode m_mode; ///<
public:
EasyTreeWidgetLoader();
~EasyTreeWidgetLoader();
int progress() const;
bool done() const;
void takeTopLevelItems(ThreadedItems& _output);
void takeItems(Items& _output);
void interrupt(bool _wait = false);
void fillTree(::profiler::timestamp_t& _beginTime, const unsigned int _blocksNumber, const ::profiler::thread_blocks_tree_t& _blocksTree, bool _colorizeRows, EasyTreeMode _mode);
void fillTreeBlocks(const::profiler_gui::TreeBlocks& _blocks, ::profiler::timestamp_t _beginTime, ::profiler::timestamp_t _left, ::profiler::timestamp_t _right, bool _strict, bool _colorizeRows, EasyTreeMode _mode);
private:
bool interrupted() const;
void setDone();
void setProgress(int _progress);
void setTreeInternal1(::profiler::timestamp_t& _beginTime, const unsigned int _blocksNumber, const ::profiler::thread_blocks_tree_t& _blocksTree, bool _colorizeRows, bool _addZeroBlocks, bool _decoratedThreadNames, ::profiler_gui::TimeUnits _units);
void setTreeInternal2(const ::profiler::timestamp_t& _beginTime, const ::profiler_gui::TreeBlocks& _blocks, ::profiler::timestamp_t _left, ::profiler::timestamp_t _right, bool _strict, bool _colorizeRows, bool _addZeroBlocks, bool _decoratedThreadNames, ::profiler_gui::TimeUnits _units);
size_t setTreeInternal(const ::profiler::BlocksTreeRoot& _threadRoot, ::profiler::block_index_t _firstCswitch, const ::profiler::timestamp_t& _beginTime, const ::profiler::BlocksTree::children_t& _children, EasyTreeWidgetItem* _parent, EasyTreeWidgetItem* _frame, ::profiler::timestamp_t _left, ::profiler::timestamp_t _right, bool _strict, ::profiler::timestamp_t& _duration, bool _colorizeRows, bool _addZeroBlocks, ::profiler_gui::TimeUnits _units);
size_t setTreeInternalPlain(const ::profiler::BlocksTreeRoot& _threadRoot, ::profiler::block_index_t _firstCswitch, const ::profiler::timestamp_t& _beginTime, const ::profiler::BlocksTree::children_t& _children, EasyTreeWidgetItem* _parent, EasyTreeWidgetItem* _frame, ::profiler::timestamp_t _left, ::profiler::timestamp_t _right, bool _strict, ::profiler::timestamp_t& _duration, bool _colorizeRows, bool _addZeroBlocks, ::profiler_gui::TimeUnits _units);
::profiler::timestamp_t calculateChildrenDurationRecursive(const ::profiler::BlocksTree::children_t& _children, ::profiler::block_id_t _id);
}; // END of class EasyTreeWidgetLoader.
//////////////////////////////////////////////////////////////////////////
#endif // EASY__TREE_WIDGET_LOADER__H_

View File

@ -0,0 +1,52 @@
#include <QStringList>
#include "treeitem.h"
TreeItem::TreeItem(const QList<QVariant> &data, TreeItem *parent)
{
m_parentItem = parent;
m_itemData = data;
}
TreeItem::~TreeItem()
{
qDeleteAll(m_childItems);
}
void TreeItem::appendChild(TreeItem *item)
{
m_childItems.append(item);
}
TreeItem *TreeItem::child(int row)
{
return m_childItems.value(row);
}
int TreeItem::childCount() const
{
return m_childItems.count();
}
int TreeItem::columnCount() const
{
return m_itemData.count();
}
QVariant TreeItem::data(int column) const
{
return m_itemData.value(column);
}
TreeItem *TreeItem::parentItem()
{
return m_parentItem;
}
int TreeItem::row() const
{
if (m_parentItem)
return m_parentItem->m_childItems.indexOf(const_cast<TreeItem*>(this));
return 0;
}

View File

@ -0,0 +1,28 @@
#ifndef TREEITEM_H
#define TREEITEM_H
#include <QList>
#include <QVariant>
class TreeItem
{
public:
explicit TreeItem(const QList<QVariant> &data, TreeItem *parentItem = 0);
~TreeItem();
void appendChild(TreeItem *child);
TreeItem *child(int row);
int childCount() const;
int columnCount() const;
QVariant data(int column) const;
int row() const;
TreeItem *parentItem();
private:
QList<TreeItem*> m_childItems;
QList<QVariant> m_itemData;
TreeItem *m_parentItem;
};
#endif // TREEITEM_H

View File

@ -0,0 +1,264 @@
#include "treeitem.h"
#include "treemodel.h"
#include "profiler/profiler.h"
#include <QStringList>
#include <QDataStream>
#include <QDebug>
TreeModel::TreeModel(const QByteArray &data, QObject *parent)
: QAbstractItemModel(parent)
{
QList<QVariant> rootData;
rootData << "Name" << "Duration ms" << "Percent" <<"thread id";
m_rootItem = new TreeItem(rootData);
setupModelData(data, m_rootItem);
}
TreeModel::~TreeModel()
{
delete m_rootItem;
}
int TreeModel::columnCount(const QModelIndex &parent) const
{
if (parent.isValid())
return static_cast<TreeItem*>(parent.internalPointer())->columnCount();
else
return m_rootItem->columnCount();
}
QVariant TreeModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();
if (role != Qt::DisplayRole)
return QVariant();
TreeItem *item = static_cast<TreeItem*>(index.internalPointer());
return item->data(index.column());
}
Qt::ItemFlags TreeModel::flags(const QModelIndex &index) const
{
if (!index.isValid())
return 0;
return QAbstractItemModel::flags(index);
}
QVariant TreeModel::headerData(int section, Qt::Orientation orientation,
int role) const
{
if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
return m_rootItem->data(section);
return QVariant();
}
QModelIndex TreeModel::index(int row, int column, const QModelIndex &parent)
const
{
if (!hasIndex(row, column, parent))
return QModelIndex();
TreeItem *parentItem;
if (!parent.isValid())
parentItem = m_rootItem;
else
parentItem = static_cast<TreeItem*>(parent.internalPointer());
TreeItem *childItem = parentItem->child(row);
if (childItem)
return createIndex(row, column, childItem);
else
return QModelIndex();
}
QModelIndex TreeModel::parent(const QModelIndex &index) const
{
if (!index.isValid())
return QModelIndex();
TreeItem *childItem = static_cast<TreeItem*>(index.internalPointer());
TreeItem *parentItem = childItem->parentItem();
if (parentItem == m_rootItem)
return QModelIndex();
return createIndex(parentItem->row(), 0, parentItem);
}
int TreeModel::rowCount(const QModelIndex &parent) const
{
TreeItem *parentItem;
if (parent.column() > 0)
return 0;
if (!parent.isValid())
parentItem = m_rootItem;
else
parentItem = static_cast<TreeItem*>(parent.internalPointer());
return parentItem->childCount();
}
void TreeModel::setupModelData(const QByteArray &lines, TreeItem *parent)
{
QList<TreeItem*> parents;
QList<int> indentations;
indentations << 0;
typedef std::map<profiler::timestamp_t, profiler::SerializedBlock> blocks_map_t;
typedef std::map<size_t, blocks_map_t> thread_map_t;
thread_map_t blocksList;
QByteArray array(lines);
QDataStream io(&array,QIODevice::ReadOnly);
while(!io.atEnd()){
uint16_t sz = 0;
io.readRawData((char*)&sz,sizeof(sz));
char* data = new char[sz];
io.readRawData(data,sz);
profiler::BaseBlockData* baseData = (profiler::BaseBlockData*)data;
blocksList[baseData->getThreadId()].emplace(
baseData->getBegin(),
/*std::move(*/profiler::SerializedBlock(sz, data))/*)*/;
}
for (auto& threads_list : blocksList){
std::list<const profiler::BaseBlockData *> parents_blocks;
parents.clear();
parents << parent;
double rootDuration = 0.0;
for (auto& i : threads_list.second){
QList<QVariant> columnData;
double percent = 0.0;
const profiler::BaseBlockData * _block = i.second.block();
profiler::timestamp_t _end = _block->getEnd();
profiler::timestamp_t _begin = _block->getBegin();
bool is_root = false;
double duration = _block->duration();
if(parents_blocks.empty()){
parents_blocks.push_back(_block);
parents << parents.last();
is_root = true;
rootDuration =duration;
}else{
auto& last_block_in_stack = parents_blocks.back();
auto last_block_end = last_block_in_stack->getEnd();
if(_begin >= last_block_end){
parents_blocks.pop_back();
parents.pop_back();
for(std::list<const profiler::BaseBlockData *>::reverse_iterator it = parents_blocks.rbegin(); it != parents_blocks.rend();){
last_block_end = (*it)->getEnd();
if(_end <= last_block_end){
break;
}else{
parents_blocks.erase( std::next(it).base() );
parents.pop_back();
}
}
}
}
if (!is_root){
parents_blocks.push_back(_block);
if(parents.size() > 1){
parents << parents.last()->child(parents.last()->childCount()-1);
}else{
parents << parents.last();
is_root = true;
}
}
if(is_root){
percent = 100.0;
rootDuration =duration;
}else{
percent = duration*100.0/rootDuration;
}
columnData << i.second.getBlockName();
columnData << QVariant::fromValue(duration/1000000.0);
columnData << percent;
columnData << QVariant::fromValue(_block->getThreadId());
if(_block->getType() == profiler::BLOCK_TYPE_BLOCK){
parents.last()->appendChild(new TreeItem(columnData, parents.last()));
}else{
//parent->appendChild(new TreeItem(columnData, parent));
parents.last()->appendChild(new TreeItem(columnData, parent));
}
}
}
return;
/*
while (number < lines.count()) {
int position = 0;
while (position < lines[number].length()) {
if (lines[number].at(position) != ' ')
break;
position++;
}
QString lineData = lines[number].mid(position).trimmed();
if (!lineData.isEmpty()) {
// Read the column data from the rest of the line.
QStringList columnStrings = lineData.split("\t", QString::SkipEmptyParts);
QList<QVariant> columnData;
for (int column = 0; column < columnStrings.count(); ++column)
columnData << columnStrings[column];
if (position > indentations.last()) {
// The last child of the current parent is now the new parent
// unless the current parent has no children.
if (parents.last()->childCount() > 0) {
parents << parents.last()->child(parents.last()->childCount()-1);
indentations << position;
}
} else {
while (position < indentations.last() && parents.count() > 0) {
parents.pop_back();
indentations.pop_back();
}
}
// Append a new item to the current parent's list of children.
parents.last()->appendChild(new TreeItem(columnData, parents.last()));
}
++number;
}
*/
}

View File

@ -0,0 +1,34 @@
#ifndef TREEMODEL_H
#define TREEMODEL_H
#include <QAbstractItemModel>
#include <QModelIndex>
#include <QVariant>
class TreeItem;
class TreeModel : public QAbstractItemModel
{
Q_OBJECT
public:
explicit TreeModel(const QByteArray &data, QObject *parent = 0);
~TreeModel();
QVariant data(const QModelIndex &index, int role) const Q_DECL_OVERRIDE;
Qt::ItemFlags flags(const QModelIndex &index) const Q_DECL_OVERRIDE;
QVariant headerData(int section, Qt::Orientation orientation,
int role = Qt::DisplayRole) const Q_DECL_OVERRIDE;
QModelIndex index(int row, int column,
const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE;
QModelIndex parent(const QModelIndex &index) const Q_DECL_OVERRIDE;
int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE;
int columnCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE;
private:
void setupModelData(const QByteArray &lines, TreeItem *parent);
TreeItem *m_rootItem;
};
#endif // TREEMODEL_H