thesis version
This commit is contained in:
commit
caf2a692f9
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
a.out
|
||||
build/
|
||||
release/
|
||||
clang/
|
||||
__pycache__/
|
173
CMakeLists.txt
Normal file
173
CMakeLists.txt
Normal file
@ -0,0 +1,173 @@
|
||||
cmake_minimum_required(VERSION 3.0)
|
||||
get_filename_component(project_name ${CMAKE_CURRENT_SOURCE_DIR} NAME)
|
||||
project(${project_name})
|
||||
|
||||
set(EXTENSION "cpp")
|
||||
|
||||
set(CMAKE_C_STANDARD 99)
|
||||
set(CMAKE_CXX_STANDARD 14)
|
||||
|
||||
set(GEN_BINARY ON)
|
||||
set(GEN_LIBRARY ON)
|
||||
set(LIB_TYPE STATIC) # NONE, STATIC, SHARED, MODULE
|
||||
set(LIBS_TYPE STATIC)
|
||||
|
||||
set(FLAGS_ANY "-Wall -Wextra -Winline -Wfatal-errors")
|
||||
set(FLAGS_DEBUG "-DDEBUG -O0 -pg")
|
||||
set(FLAGS_RELEASE "-DNDEBUG -O2")
|
||||
|
||||
set(SRCDIRS src)
|
||||
set(LIBSDIRS )
|
||||
set(LIBDIRS src/tsp)
|
||||
set(TESTSDIRS celero)
|
||||
set(EXAMPLESDIRS bench examples)
|
||||
|
||||
set(INCLUDE_DIRS "inc")
|
||||
set(LIBRARIES "-lpthread -ltbb")
|
||||
|
||||
set(celero_FLAGS "-fopenmp")
|
||||
set(celero_INCLUDE_DIRS "celero")
|
||||
set(celero_LIBRARIES "-lpthread -fopenmp")
|
||||
|
||||
set(USER_LIBRARIES "")
|
||||
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${FLAGS_ANY}")
|
||||
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${FLAGS_ANY} ${FLAGS_DEBUG}")
|
||||
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${FLAGS_ANY} ${FLAGS_RELEASE}")
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${FLAGS_ANY}")
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${FLAGS_ANY} ${FLAGS_DEBUG}")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${FLAGS_ANY} ${FLAGS_RELEASE}")
|
||||
|
||||
## Libraries
|
||||
if(NOT ${LIB_TYPE} MATCHES "^NONE$")
|
||||
# Project library
|
||||
if(GEN_LIBRARY)
|
||||
set(lib_src "")
|
||||
foreach(srcdir ${SRCDIRS})
|
||||
set(srcpath ${CMAKE_CURRENT_SOURCE_DIR}/${srcdir})
|
||||
file(GLOB_RECURSE tmpsrc ${srcpath}/*.${EXTENSION})
|
||||
list(APPEND lib_src ${tmpsrc})
|
||||
endforeach()
|
||||
|
||||
set(lib ${PROJECT_NAME})
|
||||
if(lib_src)
|
||||
message(STATUS "+ Library: ${lib}")
|
||||
add_library(${lib} ${LIB_TYPE} ${lib_src})
|
||||
target_include_directories(${lib} PUBLIC ${INCLUDE_DIRS})
|
||||
target_link_libraries(${lib} ${LIBRARIES})
|
||||
list(APPEND USER_LIBRARIES ${lib})
|
||||
else()
|
||||
message(WARNING "! Library ${lib}: no sources")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
## Other libraries
|
||||
if(NOT ${LIBS_TYPE} MATCHES "^NONE$")
|
||||
foreach(libsdir ${LIBSDIRS})
|
||||
set(libspath ${CMAKE_CURRENT_SOURCE_DIR}/${libsdir})
|
||||
file(GLOB libs RELATIVE ${libspath} ${libspath}/*)
|
||||
if(libs)
|
||||
foreach(child ${libs})
|
||||
set(lib "")
|
||||
if(IS_DIRECTORY ${libspath}/${child})
|
||||
set(lib ${child})
|
||||
list(APPEND LIBDIRS ${libsdir}/${child})
|
||||
else()
|
||||
message(WARNING "! Ignoring file: ${libsdir}/${child}")
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
foreach(libdir ${LIBDIRS})
|
||||
set(libpath ${CMAKE_CURRENT_SOURCE_DIR}/${libdir})
|
||||
file(GLOB_RECURSE lib_src ${libpath}/*.${EXTENSION})
|
||||
if(lib_src)
|
||||
get_filename_component(lib ${libpath} NAME)
|
||||
message(STATUS "+ Library: ${lib}")
|
||||
add_library(${lib} ${LIBS_TYPE} ${lib_src})
|
||||
target_include_directories(${lib} PUBLIC ${INCLUDE_DIRS})
|
||||
target_link_libraries(${lib} ${LIBRARIES})
|
||||
list(APPEND USER_LIBRARIES ${lib})
|
||||
else()
|
||||
message(WARNING "! Library ${lib}: no sources")
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
## Binary
|
||||
if(GEN_BINARY)
|
||||
set(src "")
|
||||
foreach(srcdir ${SRCDIRS})
|
||||
set(srcpath ${CMAKE_CURRENT_SOURCE_DIR}/${srcdir})
|
||||
file(GLOB_RECURSE tmpsrc ${srcpath}/*.${EXTENSION})
|
||||
list(APPEND src ${tmpsrc})
|
||||
endforeach()
|
||||
set(bin ${PROJECT_NAME})
|
||||
if(src)
|
||||
if(GEN_LIBRARY)
|
||||
set(bin ${bin}.bin)
|
||||
endif()
|
||||
message(STATUS "+ Binary: ${bin}")
|
||||
add_executable(${bin} ${src})
|
||||
target_include_directories(${bin} PUBLIC ${LIBSDIRS} ${INCLUDE_DIRS})
|
||||
target_link_libraries(${bin} ${LIBRARIES} ${USER_LIBRARIES})
|
||||
else()
|
||||
message(WARNING "! Binary ${bin}: no sources")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
## Tests
|
||||
foreach(testsdir ${TESTSDIRS})
|
||||
set(testspath ${CMAKE_CURRENT_SOURCE_DIR}/${testsdir})
|
||||
file(GLOB_RECURSE tests_src ${testspath}/*.${EXTENSION})
|
||||
if(tests_src)
|
||||
set(tests ${testsdir}_${PROJECT_NAME})
|
||||
message(STATUS "+ Tests: ${tests}")
|
||||
add_executable(${tests} ${tests_src})
|
||||
target_compile_options(${tests} PUBLIC ${${testsdir}_FLAGS})
|
||||
target_include_directories(${tests} PUBLIC ${SRCDIRS} ${LIBSDIRS} ${INCLUDE_DIRS} ${${testsdir}_INCLUDE_DIRS})
|
||||
target_link_libraries(${tests} ${LIBRARIES} ${USER_LIBRARIES} ${${testsdir}_LIBRARIES})
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
## Examples
|
||||
foreach(examplesdir ${EXAMPLESDIRS})
|
||||
set(examplespath ${CMAKE_CURRENT_SOURCE_DIR}/${examplesdir})
|
||||
file(GLOB examples RELATIVE ${examplespath} ${examplespath}/*)
|
||||
if(examples)
|
||||
foreach(child ${examples})
|
||||
set(example_bin_filename "")
|
||||
set(example "")
|
||||
if(IS_DIRECTORY ${examplespath}/${child})
|
||||
set(example_bin_filename ${child})
|
||||
set(example ${examplesdir}_${example_bin_filename})
|
||||
file(GLOB_RECURSE example_src ${examplespath}/${child}/*.${EXTENSION})
|
||||
else()
|
||||
get_filename_component(extension ${child} EXT)
|
||||
if(${extension} MATCHES "^.${EXTENSION}$")
|
||||
get_filename_component(example_name ${child} NAME_WE)
|
||||
set(example_bin_filename ${example_name})
|
||||
set(example ${examplesdir}_${example_bin_filename})
|
||||
set(example_src ${examplespath}/${child})
|
||||
endif()
|
||||
endif()
|
||||
if(example)
|
||||
if(example_src)
|
||||
message(STATUS "+ Example: ${examplesdir}/${example}")
|
||||
add_executable(${example} ${example_src})
|
||||
target_include_directories(${example} PUBLIC ${SRCDIRS} ${LIBSDIRS} ${INCLUDE_DIRS})
|
||||
target_link_libraries(${example} ${LIBRARIES} ${USER_LIBRARIES})
|
||||
set_target_properties(${example} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${examplesdir})
|
||||
set_target_properties(${example} PROPERTIES OUTPUT_NAME ${example_bin_filename})
|
||||
else()
|
||||
message(WARNING "! Example ${example}: no sources")
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
endforeach()
|
674
LICENSE
Normal file
674
LICENSE
Normal file
@ -0,0 +1,674 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://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
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
pfor
|
||||
Copyright (C) 2021 phd / dev
|
||||
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) 2021 phd / dev
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<https://www.gnu.org/licenses/>.
|
||||
|
||||
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
|
||||
<https://www.gnu.org/licenses/why-not-lgpl.html>.
|
162
README.md
Normal file
162
README.md
Normal file
@ -0,0 +1,162 @@
|
||||
# About
|
||||
|
||||
ROSA (in french "**R**echerche **O**pérationnelle grâce aux **S**quelettes **A**lgorithmiques",
|
||||
i.e. [Operational Research](https://en.wikipedia.org/wiki/Operations_research) with [Algorithmic Skeletons](https://en.wikipedia.org/wiki/Algorithmic_skeleton)).
|
||||
It relies on [alsk](https://phd.pereda.fr/dev/alsk) for the algorithmic skeletons.
|
||||
This is part of the work done for my Ph.D. thesis.
|
||||
|
||||
## Brief
|
||||
|
||||
The main algorithm implemented and presented is GRASP×ELS.
|
||||
This metaheuristic can be represented as below:
|
||||
|
||||
<div align="center"><img src="https://phd.pereda.fr/assets/rosa/graspels.png" width="800"></div>
|
||||
|
||||
When implemented as an algorithmic skeleton, its representation becomes this tree:
|
||||
|
||||
<div align="center"><img src="https://phd.pereda.fr/assets/rosa/treegraspels.png" width="500"></div>
|
||||
|
||||
Obtained using the following source code.
|
||||
|
||||
For the internal ELS:
|
||||
```cpp
|
||||
template<typename InitLS, typename Mutate, typename LS, typename InnerSelect, typename OuterSelect>
|
||||
using SkelElsStruct =
|
||||
S<alsk::Serial,
|
||||
InitLS, // LSI
|
||||
S<IterSel,
|
||||
S<FarmSel,
|
||||
S<Serial,
|
||||
Mutate, LS // M then LS
|
||||
>,
|
||||
InnerSelect // Sel3
|
||||
>,
|
||||
OuterSelect // Sel2
|
||||
>
|
||||
>;
|
||||
|
||||
template<typename Solution>
|
||||
using SkelElsLinks =
|
||||
L<Serial, R<1>(Solution const&),
|
||||
Solution(P<0>),
|
||||
L<IterSel, Solution(R<0> const&),
|
||||
L<FarmSel, Solution(Solution),
|
||||
L<Serial, R<1>(P<0>),
|
||||
Solution(P<0>, RNG&),
|
||||
Solution(R<0> const&)
|
||||
>,
|
||||
Solution(Solution const&, Solution const&)
|
||||
>,
|
||||
Solution(Solution const&, Solution const&)
|
||||
>
|
||||
>;
|
||||
|
||||
template<
|
||||
typename Solution,
|
||||
typename InitLS, typename Mutate, typename LS, typename InnerSelect, typename OuterSelect
|
||||
>
|
||||
using SkelEls = BuildSkeleton<SkelElsStruct, SkelElsLinks>::skeleton<
|
||||
Pack<InitLS, Mutate, LS, InnerSelect, OuterSelect>,
|
||||
Pack<Solution>
|
||||
>;
|
||||
```
|
||||
|
||||
For the GRASP:
|
||||
```cpp
|
||||
template<typename CH, typename LS, typename Select>
|
||||
using SkelGraspStructure =
|
||||
S<FarmSel,
|
||||
S<Serial, CH, LS>,
|
||||
Select // Sel1
|
||||
>;
|
||||
|
||||
template<typename Problem, typename Solution>
|
||||
using SkelGraspLinks =
|
||||
L<FarmSel, Solution(Problem const&),
|
||||
L<Serial, R<1>(P<0>),
|
||||
Solution(P<0>, RNG),
|
||||
Solution(R<0>)
|
||||
>,
|
||||
Solution(Solution, Solution)
|
||||
>;
|
||||
|
||||
template<typename Problem, typename Solution, typename CH, typename LS, typename Select>
|
||||
using SkelGrasp = BuildSkeleton<SkelGraspStructure, SkelGraspLinks>::skeleton<
|
||||
Pack<CH, LS, Select>,
|
||||
Pack<Problem, Solution>
|
||||
>;
|
||||
```
|
||||
|
||||
Then the GRASP×ELS can be constructed:
|
||||
```cpp
|
||||
// All arguments are defined types or functions, see full source code
|
||||
using ELS = SkelEls<
|
||||
tsp::Solution,
|
||||
Descent,
|
||||
Move2Opt, Descent,
|
||||
FN(selectMin)
|
||||
>;
|
||||
|
||||
using GRASPxELS = SkelGrasp<
|
||||
tsp::Problem, tsp::Solution,
|
||||
RGreedy<tsp::Solution>, ELS,
|
||||
FN(selectMin)
|
||||
>;
|
||||
```
|
||||
|
||||
## Performances
|
||||
|
||||
The measures shown below are from using the GRASPxELS algorithm to solve an instance of [TSP](https://en.wikipedia.org/wiki/Travelling_salesman_problem) with 194 nodes.
|
||||
Various execution policies are used:
|
||||
<ul>
|
||||
<li>"hw_seq": handwritten sequential implementation;
|
||||
<img src="https://phd.pereda.fr/assets/rosa/rt_legend.png" width="250" align="right">
|
||||
</li>
|
||||
<li>"hw_par": handwritten parallel implementation;</li>
|
||||
<li>"sk_seq": skeleton without parallelisation;</li>
|
||||
<li>"sk_firstlevel": skeleton with parallelisation of the first level;</li>
|
||||
<li>"sk_staticpool": skeleton with parallelisation using a thread pool with static task distribution;</li>
|
||||
<li>"sk_dynamicpool": skeleton with parallelisation using a classical thread pool with dynamic task distribution;</li>
|
||||
<li>"sk_thread": skeleton with parallelisation using dynamically created threads.</li>
|
||||
</ul>
|
||||
|
||||
For an execution with only one allotted core, meaning that there is no parallelisation done, we obtain the data below.
|
||||
Note that this data set do not use the legend shown above.
|
||||
All subsequent images use it.
|
||||
<div align="center"><img src="https://phd.pereda.fr/assets/rosa/rt_graspels_qa194_24_20_20_seq.png" width="500"></div>
|
||||
|
||||
For parallel executions, measures give the following data.
|
||||
|
||||
With 24 iterations for the outmost parallel loop:
|
||||
<div align="center"><img src="https://phd.pereda.fr/assets/rosa/rt_graspels_qa194_24_20_20_par.png" width="500"></div>
|
||||
<div align="center"><img src="https://phd.pereda.fr/assets/rosa/rt_graspels_qa194_20_20_20_speedup.png" width="500"></div>
|
||||
|
||||
With only 4 iterations for the outmost parallel loop:
|
||||
<div align="center"><img src="https://phd.pereda.fr/assets/rosa/rt_graspels_qa194_v4_20_20_par.png" width="500"></div>
|
||||
<div align="center"><img src="https://phd.pereda.fr/assets/rosa/rt_graspels_qa194_4_20_20_speedup.png" width="500"></div>
|
||||
|
||||
## Related publications
|
||||
|
||||
- "Repeatability with Random Numbers Using Algorithmic Skeletons", ESM 2020 (https://hal.archives-ouvertes.fr/hal-02980472);
|
||||
- "Modeling Algorithmic Skeletons for Automatic Parallelization Using Template Metaprogramming", HPCS 2019 (IEEE) [10.1109/HPCS48598.2019.9188128](https://doi.org/10.1109/HPCS48598.2019.9188128);
|
||||
- "Processing Algorithmic Skeletons at Compile-Time", ROADEF 2020 (https://hal.archives-ouvertes.fr/hal-02573660);
|
||||
- "Algorithmic Skeletons Using Template Metaprogramming", ICAST 2019;
|
||||
- "Parallel Algorithmic Skeletons for Metaheuristics", ROADEF 2019 (https://hal.archives-ouvertes.fr/hal-02059533).
|
||||
|
||||
## Organisation
|
||||
|
||||
Main directories:
|
||||
- `src`: sources;
|
||||
- `src/rosa`: the library sources;
|
||||
- `rtbenchmarks`: scripts for compile-time/run-time benchmarking;
|
||||
- `results`: results presented in the thesis, obtained using mentioned scripts and codes.
|
||||
|
||||
## Usage
|
||||
|
||||
To produce the `Makefile` and build the project:
|
||||
```bash
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -DCMAKE_BUILD_TYPE=Release ..
|
||||
make
|
||||
```
|
106
bench/graspels/bad_graspels.h
Normal file
106
bench/graspels/bad_graspels.h
Normal file
@ -0,0 +1,106 @@
|
||||
#ifndef ROSA_BENCH_GRASPELS_BAD_GRASPELS_H
|
||||
#define ROSA_BENCH_GRASPELS_BAD_GRASPELS_H
|
||||
|
||||
#include <alsk/alsk.h>
|
||||
|
||||
namespace rosa {
|
||||
|
||||
/* GRASP
|
||||
* loop
|
||||
* * s = init()
|
||||
* * s = ls(s)
|
||||
* * best = select(s, best)
|
||||
* ----
|
||||
* return best
|
||||
*/
|
||||
template<typename Init, typename LS, typename Select>
|
||||
using SkelNRGraspStructure =
|
||||
alsk::S<alsk::FarmSel,
|
||||
alsk::S<alsk::Serial, Init, LS>,
|
||||
Select
|
||||
>;
|
||||
|
||||
template<typename Problem, typename Solution, typename RNG>
|
||||
using SkelNRGraspLinks =
|
||||
alsk::L<alsk::FarmSel, Solution(Problem const&, RNG&),
|
||||
alsk::L<alsk::Serial, alsk::arg::R<1>(alsk::arg::P<0>, alsk::arg::P<1>),
|
||||
Solution(alsk::arg::P<0>, alsk::arg::P<1>),
|
||||
Solution(alsk::arg::R<0> const&, alsk::arg::P<1>)
|
||||
>,
|
||||
Solution(Solution const&, Solution const&)
|
||||
>;
|
||||
|
||||
/* *** */
|
||||
|
||||
template<
|
||||
typename Problem, typename Solution, typename RNG,
|
||||
typename Init, typename LS, typename Select
|
||||
>
|
||||
using SkelNRGrasp = alsk::BuildSkeleton<SkelNRGraspStructure, SkelNRGraspLinks>::skeleton<
|
||||
tmp::Pack<Init, LS, Select>,
|
||||
tmp::Pack<Problem, Solution, RNG>
|
||||
>;
|
||||
|
||||
}
|
||||
|
||||
namespace rosa {
|
||||
|
||||
/* ELS
|
||||
* best = ls(s) -- SEls
|
||||
* loop -- SElsOuterLoop
|
||||
* * loop -- SElsInnerLoop
|
||||
* * * s = mutate(best) -- SElsGen
|
||||
* * * s = ls(s)
|
||||
* * * ibest = select(s, ibest)
|
||||
* * ----
|
||||
* * best = select(s, best) // with acceptation criteria?
|
||||
* ----
|
||||
* return best
|
||||
*/
|
||||
template<
|
||||
typename InitLS, typename Mutate, typename LS,
|
||||
typename InnerSelect, typename OuterSelect
|
||||
>
|
||||
using SkelNRElsStruct =
|
||||
alsk::S<alsk::Serial,
|
||||
InitLS,
|
||||
alsk::S<alsk::IterSel,
|
||||
alsk::S<alsk::FarmSel,
|
||||
alsk::S<alsk::Serial,
|
||||
Mutate, LS
|
||||
>,
|
||||
InnerSelect
|
||||
>,
|
||||
OuterSelect
|
||||
>
|
||||
>;
|
||||
|
||||
template<typename Solution, typename RNG>
|
||||
using SkelNRElsLinks =
|
||||
alsk::L<alsk::Serial, alsk::arg::R<1>(Solution const&, RNG&),
|
||||
Solution(alsk::arg::P<0>),
|
||||
alsk::L<alsk::IterSel, Solution(alsk::arg::R<0> const&, alsk::arg::P<1>),
|
||||
alsk::L<alsk::FarmSel, Solution(Solution const&, alsk::arg::P<1>),
|
||||
alsk::L<alsk::Serial, alsk::arg::R<1>(alsk::arg::P<0>, alsk::arg::P<1>),
|
||||
Solution(alsk::arg::P<0>, alsk::arg::P<1>),
|
||||
Solution(alsk::arg::R<0> const&)
|
||||
>,
|
||||
Solution(Solution const&, Solution const&)
|
||||
>,
|
||||
Solution(Solution const&, Solution const&)
|
||||
>
|
||||
>;
|
||||
|
||||
template<
|
||||
typename Solution, typename RNG,
|
||||
typename InitLS, typename Mutate, typename LS,
|
||||
typename InnerSelect, typename OuterSelect = InnerSelect
|
||||
>
|
||||
using SkelNREls = alsk::BuildSkeleton<SkelNRElsStruct, SkelNRElsLinks>::skeleton<
|
||||
tmp::Pack<InitLS, Mutate, LS, InnerSelect, OuterSelect>,
|
||||
tmp::Pack<Solution, RNG>
|
||||
>;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
86
bench/graspels/common.h
Normal file
86
bench/graspels/common.h
Normal file
@ -0,0 +1,86 @@
|
||||
#ifndef ROSA_BENCH_GRASPELS_COMMON_H
|
||||
#define ROSA_BENCH_GRASPELS_COMMON_H
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <random>
|
||||
#include <thread>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <alsk/alsk.h>
|
||||
|
||||
#include <muscles/descent.h>
|
||||
#include <muscles/move2opt.h>
|
||||
#include <muscles/rgreedy.h>
|
||||
|
||||
#include <rosa/els.h>
|
||||
#include <rosa/grasp.h>
|
||||
|
||||
#include <tsp/solution.h>
|
||||
#include <tsp/problem.h>
|
||||
#include <tsp/tsp.h>
|
||||
|
||||
#ifndef DATA_FILE
|
||||
#define DATA_FILE "../data/qa194"
|
||||
#endif
|
||||
#ifndef GRASP_N
|
||||
#define GRASP_N 2
|
||||
#endif
|
||||
#ifndef ELS_ITER_MAX
|
||||
#define ELS_ITER_MAX 20
|
||||
#endif
|
||||
#ifndef ELS_GEN
|
||||
#define ELS_GEN 10
|
||||
#endif
|
||||
#ifndef FUNC
|
||||
#define FUNC none
|
||||
#endif
|
||||
#ifndef NTHREADS
|
||||
#define NTHREADS 1
|
||||
#endif
|
||||
#ifndef SEED
|
||||
#define SEED std::mt19937::default_seed
|
||||
#endif
|
||||
|
||||
#define STR_(A) #A
|
||||
#define STR(A) STR_(A)
|
||||
|
||||
/* repeatable* */
|
||||
#define REPRODUCIBLE
|
||||
|
||||
using RNG = std::mt19937;
|
||||
|
||||
struct Arguments {
|
||||
std::mt19937::result_type seed;
|
||||
};
|
||||
|
||||
inline tsp::Solution selectMin(tsp::Solution const& a, tsp::Solution const& b) { return a<b? a:b; }
|
||||
inline auto rgreedy() { return RGreedy<tsp::Solution>{2}; }
|
||||
|
||||
inline double tvdiff(struct timeval& b, struct timeval& e) {
|
||||
return (e.tv_sec - b.tv_sec) + (e.tv_usec - b.tv_usec) / 1e6;
|
||||
}
|
||||
|
||||
template<typename F, typename... Args>
|
||||
void timeit(int who, std::string const& prefix, F&& f, Args&&... args) {
|
||||
using Clock = std::chrono::high_resolution_clock;
|
||||
|
||||
struct rusage b, e;
|
||||
|
||||
auto tp0 = Clock::now();
|
||||
getrusage(who, &b);
|
||||
std::forward<F>(f)(std::forward<Args>(args)...);
|
||||
getrusage(who, &e);
|
||||
auto tp1 = Clock::now();
|
||||
|
||||
std::cout << prefix;
|
||||
std::cout << "[" << std::this_thread::get_id() << "] ";
|
||||
std::cout << "time: ";
|
||||
std::cout << "real " << std::chrono::duration<double>(tp1 - tp0).count() << " ";
|
||||
std::cout << "user " << tvdiff(b.ru_utime, e.ru_utime) << " ";
|
||||
std::cout << "sys " << tvdiff(b.ru_stime, e.ru_stime);
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
#endif
|
26
bench/graspels/decl.h
Normal file
26
bench/graspels/decl.h
Normal file
@ -0,0 +1,26 @@
|
||||
#ifndef ROSA_BENCH_GRASPELS_DECL_H
|
||||
#define ROSA_BENCH_GRASPELS_DECL_H
|
||||
|
||||
#include "common.h"
|
||||
|
||||
tsp::Solution none(tsp::Problem const&, RNG&, Arguments const&);
|
||||
|
||||
tsp::Solution hwElsGen(tsp::Solution const&, RNG&, Arguments const&);
|
||||
tsp::Solution hw_seq(tsp::Problem const&, RNG&, Arguments const&);
|
||||
tsp::Solution hw_par(tsp::Problem const&, RNG&, Arguments const&);
|
||||
|
||||
tsp::Solution hw_seq_v(tsp::Problem const&, RNG&, Arguments const&);
|
||||
tsp::Solution hw_par_v(tsp::Problem const&, RNG&, Arguments const&);
|
||||
|
||||
tsp::Solution sk_nr_seq(tsp::Problem const&, RNG&, Arguments const&);
|
||||
tsp::Solution sk_nr_par(tsp::Problem const&, RNG&, Arguments const&);
|
||||
|
||||
tsp::Solution sk_seq(tsp::Problem const&, RNG&, Arguments const&);
|
||||
tsp::Solution sk_par_firstlevel(tsp::Problem const&, RNG&, Arguments const&);
|
||||
tsp::Solution sk_par_staticpool(tsp::Problem const&, RNG&, Arguments const&);
|
||||
tsp::Solution sk_par_dynamicpool(tsp::Problem const&, RNG&, Arguments const&);
|
||||
tsp::Solution sk_par_thread(tsp::Problem const&, RNG&, Arguments const&);
|
||||
|
||||
tsp::Solution tbb_par(tsp::Problem const&, RNG&, Arguments const&);
|
||||
|
||||
#endif
|
220
bench/graspels/hw.cpp
Normal file
220
bench/graspels/hw.cpp
Normal file
@ -0,0 +1,220 @@
|
||||
#include "common.h"
|
||||
|
||||
auto hwElsGen(tsp::Solution const& solution, RNG& rng) {
|
||||
return Descent{}(Move2Opt{}(solution, rng));
|
||||
}
|
||||
|
||||
#if PARLEV==2
|
||||
auto hwElsInner(tsp::Solution const& solution, RNG& rng, std::size_t nCore) {
|
||||
std::size_t const nThreads = std::min<std::size_t>(nCore, ELS_GEN);
|
||||
std::size_t const step = ELS_GEN/nThreads;
|
||||
std::size_t remain = ELS_GEN - step*nThreads;
|
||||
|
||||
// std::cout << "LEVEL #2 : " << nCore << ";" << nThreads << ";" << step << ";" << remain << std::endl;
|
||||
|
||||
std::vector<std::thread> threads{nThreads-1};
|
||||
std::vector<tsp::Solution> solutions(nThreads);
|
||||
|
||||
tsp::Solution best;
|
||||
|
||||
/* repeatability at loop level */
|
||||
std::vector<RNG> rngs(ELS_GEN);
|
||||
for(std::size_t i = 0; i < ELS_GEN; ++i)
|
||||
rngs[i].seed(rng());
|
||||
/* ***** */
|
||||
|
||||
std::size_t start{};
|
||||
|
||||
for(std::size_t i{}; i < (nThreads-1); ++i) {
|
||||
std::size_t offset = !!remain;
|
||||
remain -= offset;
|
||||
|
||||
threads[i] = std::thread{
|
||||
[&,start,i,step=step+offset](auto const& solution) {
|
||||
tsp::Solution& s = solutions[i];
|
||||
|
||||
for(std::size_t j{}; j < step; ++j) {
|
||||
tsp::Solution cur = hwElsGen(solution, rngs[start+j]);
|
||||
s = selectMin(std::move(s), std::move(cur));
|
||||
}
|
||||
},
|
||||
std::cref(solution)
|
||||
};
|
||||
|
||||
start += step+offset;
|
||||
}
|
||||
|
||||
{
|
||||
tsp::Solution& s = solutions[nThreads-1];
|
||||
|
||||
for(std::size_t j{}; j < step; ++j) {
|
||||
tsp::Solution cur = hwElsGen(solution, rngs[start+j]);
|
||||
s = selectMin(std::move(s), std::move(cur));
|
||||
}
|
||||
}
|
||||
|
||||
for(auto& thread: threads) thread.join();
|
||||
|
||||
best = *std::min_element(std::begin(solutions), std::end(solutions));
|
||||
|
||||
return best;
|
||||
}
|
||||
#else
|
||||
auto hwElsInner(tsp::Solution const& solution, RNG& rng, std::size_t) {
|
||||
tsp::Solution best;
|
||||
|
||||
/* repeatability at loop level */
|
||||
std::vector<RNG> rngs(ELS_GEN);
|
||||
for(std::size_t i = 0; i < ELS_GEN; ++i)
|
||||
rngs[i].seed(rng());
|
||||
/* ***** */
|
||||
|
||||
if(ELS_GEN)
|
||||
best = hwElsGen(solution, rngs[0]);
|
||||
|
||||
for(std::size_t i = 1; i < ELS_GEN; ++i) {
|
||||
tsp::Solution current = hwElsGen(solution, rngs[i]);
|
||||
best = selectMin(std::move(best), std::move(current));
|
||||
}
|
||||
|
||||
return best;
|
||||
}
|
||||
#endif
|
||||
|
||||
auto hwEls(tsp::Solution const& solution, RNG& rng, std::size_t nCore) {
|
||||
tsp::Solution best = Descent{}(solution);
|
||||
|
||||
for(std::size_t i = 0; i < ELS_ITER_MAX; ++i) {
|
||||
tsp::Solution current = hwElsInner(best, rng, nCore);
|
||||
best = selectMin(std::move(best), std::move(current));
|
||||
}
|
||||
|
||||
return best;
|
||||
}
|
||||
|
||||
auto hwGraspGen(tsp::Problem const& problem, RNG& rng, std::size_t nCore = 1) {
|
||||
return hwEls(rgreedy()(problem, rng), rng, nCore);
|
||||
}
|
||||
|
||||
/* *** */
|
||||
|
||||
auto hwGraspEls(tsp::Problem const& problem, RNG& rng) {
|
||||
tsp::Solution best;
|
||||
|
||||
/* repeatability at loop level */
|
||||
std::vector<RNG> rngs(GRASP_N);
|
||||
for(std::size_t i = 0; i < GRASP_N; ++i)
|
||||
rngs[i].seed(rng());
|
||||
/* ***** */
|
||||
|
||||
if(GRASP_N)
|
||||
best = hwGraspGen(problem, rngs[0]);
|
||||
for(std::size_t i = 1; i < GRASP_N; ++i) {
|
||||
tsp::Solution current = hwGraspGen(problem, rngs[i]);
|
||||
best = selectMin(std::move(best), std::move(current));
|
||||
}
|
||||
|
||||
return best;
|
||||
}
|
||||
|
||||
template<std::size_t K>
|
||||
auto hwGraspElsPar(tsp::Problem const& problem, RNG& rng) {
|
||||
std::size_t const nThreads = std::min<std::size_t>(K, GRASP_N);
|
||||
std::size_t const step = GRASP_N/nThreads;
|
||||
std::size_t const remain = GRASP_N - step*nThreads;
|
||||
|
||||
std::size_t cores2a = K/nThreads;
|
||||
std::size_t cores2b = (remain==0 ? 1 : K/remain);
|
||||
|
||||
// std::cout << "LEVEL #1 : " << K << ";" << nThreads << ";" << step << ";" << remain << std::endl;
|
||||
|
||||
tsp::Solution best;
|
||||
|
||||
std::vector<std::thread> threadsA{nThreads-1};
|
||||
std::vector<std::thread> threadsB{remain==0 ? 0 : remain-1};
|
||||
|
||||
std::vector<tsp::Solution> solutions(nThreads+remain);
|
||||
|
||||
/* repeatability at loop level */
|
||||
std::vector<RNG> rngs(GRASP_N);
|
||||
for(std::size_t i = 0; i < GRASP_N; ++i)
|
||||
rngs[i].seed(rng());
|
||||
/* ***** */
|
||||
|
||||
std::size_t start{};
|
||||
std::size_t i{};
|
||||
|
||||
/* Loop A */
|
||||
for(; i < (nThreads-1); ++i) {
|
||||
threadsA[i] = std::thread{
|
||||
[&,start,i,cores2a](auto const& problem) {
|
||||
tsp::Solution& s = solutions[i];
|
||||
|
||||
for(std::size_t j{}; j < step; ++j) {
|
||||
tsp::Solution cur = hwGraspGen(problem, rngs[start+j],cores2a);
|
||||
s = selectMin(std::move(s), std::move(cur));
|
||||
}
|
||||
},
|
||||
std::cref(problem)
|
||||
};
|
||||
|
||||
start += step;
|
||||
}
|
||||
|
||||
{
|
||||
tsp::Solution& s = solutions[i];
|
||||
|
||||
for(std::size_t j{}; j < step; ++j) {
|
||||
tsp::Solution cur = hwGraspGen(problem, rngs[start+j],cores2a);
|
||||
s = selectMin(std::move(s), std::move(cur));
|
||||
}
|
||||
|
||||
start+=step;
|
||||
++i;
|
||||
}
|
||||
|
||||
for(auto& thread: threadsA) thread.join();
|
||||
|
||||
/* Loop B */
|
||||
for(; i < nThreads+remain-1; ++i) {
|
||||
threadsB[i-nThreads] = std::thread{
|
||||
[&,start,i,cores2b](auto const& problem) {
|
||||
tsp::Solution& s = solutions[i];
|
||||
|
||||
tsp::Solution cur = hwGraspGen(problem, rngs[start],cores2b);
|
||||
s = selectMin(std::move(s), std::move(cur));
|
||||
},
|
||||
std::cref(problem)
|
||||
};
|
||||
|
||||
++start;
|
||||
}
|
||||
|
||||
if (remain>0)
|
||||
{
|
||||
tsp::Solution& s = solutions[i];
|
||||
|
||||
tsp::Solution cur = hwGraspGen(problem, rngs[start],cores2b);
|
||||
s = selectMin(std::move(s), std::move(cur));
|
||||
++start;
|
||||
++i;
|
||||
}
|
||||
|
||||
for(auto& thread: threadsB) thread.join();
|
||||
|
||||
/* Selection */
|
||||
|
||||
best = *std::min_element(std::begin(solutions), std::end(solutions));
|
||||
|
||||
return best;
|
||||
}
|
||||
|
||||
/* *** */
|
||||
|
||||
tsp::Solution hw_seq(tsp::Problem const& p, RNG& rng, Arguments const&) {
|
||||
return hwGraspEls(p, rng);
|
||||
}
|
||||
|
||||
tsp::Solution hw_par(tsp::Problem const& p, RNG& rng, Arguments const&) {
|
||||
return hwGraspElsPar<NTHREADS>(p, rng);
|
||||
}
|
188
bench/graspels/hwv.cpp
Normal file
188
bench/graspels/hwv.cpp
Normal file
@ -0,0 +1,188 @@
|
||||
#include "common.h"
|
||||
|
||||
auto hwElsGenV(tsp::Solution const& solution, RNG& rng) {
|
||||
return Descent{}(Move2Opt{}(solution, rng));
|
||||
}
|
||||
|
||||
auto hwElsInner(tsp::Solution const& solution, std::vector<RNG>& rngs, std::size_t id, std::size_t nCore) {
|
||||
std::size_t n = ELS_GEN;
|
||||
std::size_t maxThreads = nCore;
|
||||
|
||||
std::size_t const nThreads = std::min<std::size_t>(maxThreads, ELS_GEN);
|
||||
|
||||
std::vector<std::thread> threads{nThreads-1};
|
||||
std::size_t const step = n/nThreads;
|
||||
std::size_t const remainBase = n - step*nThreads;
|
||||
std::size_t remain = remainBase;
|
||||
|
||||
auto run = [&solution,&rngs](tsp::Solution& out, std::size_t id, std::size_t k) {
|
||||
tsp::Solution best{};
|
||||
|
||||
if(k)
|
||||
best = hwElsGenV(solution, rngs[id]);
|
||||
for(std::size_t i = 1; i < k; ++i) {
|
||||
tsp::Solution current = hwElsGenV(solution, rngs[id+i]);
|
||||
best = selectMin(std::move(best), std::move(current));
|
||||
}
|
||||
|
||||
out = std::move(best);
|
||||
};
|
||||
|
||||
std::size_t start{};
|
||||
std::vector<tsp::Solution> bests(nThreads);
|
||||
|
||||
for(std::size_t i = 0; i < nThreads-1; ++i) {
|
||||
std::size_t offset = !!remain;
|
||||
remain -= offset;
|
||||
threads[i] = std::thread{run, std::ref(bests[i]), id+start, step+offset};
|
||||
start += step+offset;
|
||||
}
|
||||
|
||||
run(bests[nThreads-1], id+start, step);
|
||||
|
||||
for(auto& thread: threads) thread.join();
|
||||
|
||||
tsp::Solution best;
|
||||
// best = *std::min_element(std::begin(solutions), std::end(solutions));
|
||||
if(nThreads) best = std::move(bests[0]);
|
||||
for(std::size_t i = 1; i < nThreads; ++i)
|
||||
best = selectMin(std::move(best), std::move(bests[i]));
|
||||
|
||||
return best;
|
||||
}
|
||||
|
||||
auto hwEls(tsp::Solution const& solution, std::vector<RNG>& rngs, std::size_t id, std::size_t nCore) {
|
||||
tsp::Solution best = Descent{}(solution);
|
||||
|
||||
for(std::size_t i = 0; i < ELS_ITER_MAX; ++i) {
|
||||
tsp::Solution current = hwElsInner(best, rngs, id, nCore);
|
||||
best = selectMin(std::move(best), std::move(current));
|
||||
}
|
||||
|
||||
return best;
|
||||
}
|
||||
|
||||
auto hwGraspGen(tsp::Problem const& problem, std::vector<RNG>& rngs, std::size_t id, std::size_t nCore = 1) {
|
||||
return hwEls(rgreedy()(problem, rngs[id]), rngs, id, nCore);
|
||||
}
|
||||
|
||||
/* *** */
|
||||
|
||||
auto hwGraspEls(tsp::Problem const& problem, std::vector<RNG>& rngs) {
|
||||
tsp::Solution best;
|
||||
|
||||
auto graspIter = [&](tsp::Problem const& problem, tsp::Solution& s, std::size_t id) {
|
||||
tsp::Solution cur = hwGraspGen(problem, rngs, id);
|
||||
s = selectMin(std::move(s), std::move(cur));
|
||||
};
|
||||
|
||||
if(GRASP_N) {
|
||||
auto graspInit = [&](tsp::Problem const& problem, tsp::Solution& s) {
|
||||
s = hwGraspGen(problem, rngs, 0);
|
||||
};
|
||||
#ifdef SUBTIME
|
||||
timeit(RUSAGE_THREAD, "[GRASP] ", graspInit, problem, best);
|
||||
#else
|
||||
graspInit(problem, best);
|
||||
#endif
|
||||
}
|
||||
|
||||
for(std::size_t i = 1; i < GRASP_N; ++i) {
|
||||
#ifdef SUBTIME
|
||||
timeit(RUSAGE_THREAD, "[GRASP] ", graspIter, problem, best, i*ELS_GEN);
|
||||
#else
|
||||
graspIter(problem, best, i*ELS_GEN);
|
||||
#endif
|
||||
}
|
||||
|
||||
return best;
|
||||
}
|
||||
|
||||
template<std::size_t K>
|
||||
auto hwGraspElsPar(tsp::Problem const& problem, std::vector<RNG>& rngs) {
|
||||
std::size_t const n = GRASP_N;
|
||||
std::size_t const maxThreads = K;
|
||||
|
||||
std::size_t const nThreads = std::min<std::size_t>(maxThreads, n);
|
||||
std::size_t const cores = maxThreads/nThreads;
|
||||
|
||||
std::vector<std::thread> threads(nThreads-1);
|
||||
std::size_t const step = n/nThreads;
|
||||
std::size_t const remainBase = n - step*nThreads;
|
||||
std::size_t remain = remainBase;
|
||||
|
||||
auto iter0 = [&problem,&rngs](tsp::Solution& best, std::size_t id, std::size_t cores) {
|
||||
best = hwGraspGen(problem, rngs, id, cores);
|
||||
};
|
||||
auto iter = [&problem,&rngs](tsp::Solution& best, std::size_t id, std::size_t cores) {
|
||||
tsp::Solution current = hwGraspGen(problem, rngs, id, cores);
|
||||
best = selectMin(std::move(best), std::move(current));
|
||||
};
|
||||
|
||||
auto run = [&](tsp::Solution& out, std::size_t id, std::size_t k, std::size_t cores) {
|
||||
tsp::Solution best{};
|
||||
|
||||
if(k) {
|
||||
#ifdef SUBTIME
|
||||
timeit(RUSAGE_THREAD, "[GRASP] ", iter0, best, id*ELS_GEN, cores);
|
||||
#else
|
||||
iter0(best, id*ELS_GEN, cores);
|
||||
#endif
|
||||
}
|
||||
|
||||
for(std::size_t i = 1; i < k; ++i) {
|
||||
#ifdef SUBTIME
|
||||
timeit(RUSAGE_THREAD, "[GRASP] ", iter, best, (id+i)*ELS_GEN, cores);
|
||||
#else
|
||||
iter(best, (id+1)*ELS_GEN, cores);
|
||||
#endif
|
||||
}
|
||||
|
||||
out = std::move(best);
|
||||
};
|
||||
|
||||
std::size_t start{};
|
||||
std::vector<tsp::Solution> bests(nThreads);
|
||||
|
||||
for(std::size_t i = 0; i < nThreads-1; ++i) {
|
||||
std::size_t offset = !!remain;
|
||||
remain -= offset;
|
||||
threads[i] = std::thread{run, std::ref(bests[i]), start, step+offset, cores};
|
||||
start += step+offset;
|
||||
}
|
||||
|
||||
run(bests[nThreads-1], start, step, cores);
|
||||
|
||||
for(std::thread& thread: threads) thread.join();
|
||||
|
||||
tsp::Solution best;
|
||||
if(nThreads) best = std::move(bests[0]);
|
||||
for(std::size_t i = 1; i < nThreads; ++i)
|
||||
best = selectMin(std::move(best), std::move(bests[i]));
|
||||
|
||||
return best;
|
||||
}
|
||||
|
||||
/* *** */
|
||||
|
||||
tsp::Solution hw_seq_v(tsp::Problem const& p, RNG& seeder, Arguments const&) {
|
||||
std::size_t n = GRASP_N * ELS_GEN;
|
||||
|
||||
std::vector<RNG> rngs;
|
||||
rngs.reserve(n);
|
||||
for(std::size_t i = 0; i < n; ++i)
|
||||
rngs.emplace_back(seeder());
|
||||
|
||||
return hwGraspEls(p, rngs);
|
||||
}
|
||||
|
||||
tsp::Solution hw_par_v(tsp::Problem const& p, RNG& seeder, Arguments const&) {
|
||||
std::size_t n = GRASP_N * ELS_GEN;
|
||||
|
||||
std::vector<RNG> rngs;
|
||||
rngs.reserve(n);
|
||||
for(std::size_t i = 0; i < n; ++i)
|
||||
rngs.emplace_back(seeder());
|
||||
|
||||
return hwGraspElsPar<NTHREADS>(p, rngs);
|
||||
}
|
49
bench/graspels/main.cpp
Normal file
49
bench/graspels/main.cpp
Normal file
@ -0,0 +1,49 @@
|
||||
#include <getopt.h>
|
||||
#include <sstream>
|
||||
|
||||
#include "common.h"
|
||||
#include "decl.h"
|
||||
|
||||
Arguments cli(int argc, char **argv) {
|
||||
int option_index, option;
|
||||
struct option long_options[] = {
|
||||
{"seed", required_argument, 0, 's' },
|
||||
{0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
Arguments args;
|
||||
args.seed = SEED;
|
||||
|
||||
optind = 0;
|
||||
while((option = getopt_long(argc, argv,
|
||||
"" "" "" "s:",
|
||||
long_options, &option_index)) != -1) {
|
||||
switch(option) {
|
||||
case 's': {
|
||||
std::istringstream iss{optarg};
|
||||
iss >> args.seed;
|
||||
} break;
|
||||
default:;
|
||||
}
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
Arguments args = cli(argc, argv);
|
||||
|
||||
tsp::Tsp tspData{DATA_FILE};
|
||||
tsp::Problem problem{tspData.points()};
|
||||
RNG rng{args.seed};
|
||||
|
||||
std::printf("conf: f: %s, data: %s, grasp: %s, outer: %s, inner: %s, threads: %s, seed: %zu\n",
|
||||
STR(FUNC), STR(DATA_FILE), STR(GRASP_N), STR(ELS_ITER_MAX), STR(ELS_GEN), STR(NTHREADS), args.seed);
|
||||
|
||||
tsp::Solution s;
|
||||
auto task = [&]{ s = FUNC(problem, rng, args); };
|
||||
|
||||
timeit(RUSAGE_SELF, "", task);
|
||||
|
||||
std::cout << "result: " << s.value() << std::endl;
|
||||
}
|
18
bench/graspels/none.cpp
Normal file
18
bench/graspels/none.cpp
Normal file
@ -0,0 +1,18 @@
|
||||
#include "common.h"
|
||||
|
||||
tsp::Solution none(tsp::Problem const&, RNG&, Arguments const&) {
|
||||
std::cout << 1+R"(
|
||||
Options:
|
||||
- DATA_FILE
|
||||
- GRASP_N
|
||||
- ELS_ITER_MAX
|
||||
- ELS_GEN
|
||||
- FUNC (mandatory)
|
||||
|
||||
Example:
|
||||
- g++ -Wall -Wextra -O2 -Isrc -Iinc -pthread src/tsp/*.cpp -DFUNC=sk_par2 -DNTHREADS=4 bench/graspels/*.cpp
|
||||
)";
|
||||
|
||||
return {};
|
||||
}
|
||||
|
37
bench/graspels/nrsk.cpp
Normal file
37
bench/graspels/nrsk.cpp
Normal file
@ -0,0 +1,37 @@
|
||||
#include "bad_graspels.h"
|
||||
#include "common.h"
|
||||
|
||||
using NRELS = rosa::SkelNREls<
|
||||
tsp::Solution, RNG,
|
||||
Descent,
|
||||
Move2Opt, Descent, FN(selectMin)
|
||||
>;
|
||||
|
||||
using NRGRASPxELS = rosa::SkelNRGrasp<
|
||||
tsp::Problem, tsp::Solution, RNG,
|
||||
RGreedy<tsp::Solution>, NRELS,
|
||||
FN(selectMin)
|
||||
>;
|
||||
|
||||
tsp::Solution sk_nr_seq(tsp::Problem const& p, RNG& rng, Arguments const&) {
|
||||
auto graspEls = alsk::implement<alsk::exec::Sequential, NRGRASPxELS>();
|
||||
graspEls.executor.repeatability.disabled();
|
||||
graspEls.skeleton.task.task<0>() = rgreedy();
|
||||
graspEls.skeleton.task.task<1>().task<1>().n = ELS_ITER_MAX;
|
||||
graspEls.skeleton.task.task<1>().task<1>().task.n = ELS_GEN;
|
||||
graspEls.skeleton.n = GRASP_N;
|
||||
|
||||
return graspEls(p, rng);
|
||||
}
|
||||
|
||||
tsp::Solution sk_nr_par(tsp::Problem const& p, RNG& rng, Arguments const&) {
|
||||
auto graspEls = alsk::implement<alsk::exec::FirstLevelNoOpti, NRGRASPxELS>();
|
||||
graspEls.executor.cores = NTHREADS;
|
||||
graspEls.executor.repeatability.disabled();
|
||||
graspEls.skeleton.task.task<0>() = rgreedy();
|
||||
graspEls.skeleton.task.task<1>().task<1>().n = ELS_ITER_MAX;
|
||||
graspEls.skeleton.task.task<1>().task<1>().task.n = ELS_GEN;
|
||||
graspEls.skeleton.n = GRASP_N;
|
||||
|
||||
return graspEls(p, rng);
|
||||
}
|
74
bench/graspels/sk.cpp
Normal file
74
bench/graspels/sk.cpp
Normal file
@ -0,0 +1,74 @@
|
||||
#include "common.h"
|
||||
|
||||
using ELS = rosa::SkelEls<
|
||||
tsp::Solution,
|
||||
Descent,
|
||||
Move2Opt, Descent, FN(selectMin)
|
||||
>;
|
||||
|
||||
using GRASPxELS = rosa::SkelGrasp<
|
||||
tsp::Problem, tsp::Solution,
|
||||
RGreedy<tsp::Solution>, ELS,
|
||||
FN(selectMin)
|
||||
>;
|
||||
|
||||
tsp::Solution sk_seq(tsp::Problem const& p, RNG&, Arguments const& args) {
|
||||
auto graspEls = alsk::implement<alsk::exec::Sequential, GRASPxELS>();
|
||||
graspEls.executor.repeatability.upTo(4);
|
||||
graspEls.state.context.seed = args.seed;
|
||||
graspEls.executor.cores = 1;
|
||||
graspEls.skeleton.task.task<0>() = rgreedy();
|
||||
graspEls.skeleton.task.task<1>().task<1>().n = ELS_ITER_MAX;
|
||||
graspEls.skeleton.task.task<1>().task<1>().task.n = ELS_GEN;
|
||||
graspEls.skeleton.n = GRASP_N;
|
||||
|
||||
return graspEls(p);
|
||||
}
|
||||
|
||||
tsp::Solution sk_par_firstlevel(tsp::Problem const& p, RNG&, Arguments const& args) {
|
||||
auto graspEls = alsk::implement<alsk::exec::FirstLevelEqui, GRASPxELS>();
|
||||
graspEls.executor.repeatability.upTo(4);
|
||||
graspEls.state.context.seed = args.seed;
|
||||
graspEls.executor.cores = NTHREADS;
|
||||
graspEls.skeleton.task.task<0>() = rgreedy();
|
||||
graspEls.skeleton.task.task<1>().task<1>().n = ELS_ITER_MAX;
|
||||
graspEls.skeleton.task.task<1>().task<1>().task.n = ELS_GEN;
|
||||
graspEls.skeleton.n = GRASP_N;
|
||||
|
||||
return graspEls(p);
|
||||
}
|
||||
|
||||
tsp::Solution sk_par_staticpool(tsp::Problem const& p, RNG&, Arguments const& args) {
|
||||
auto graspEls = alsk::implement<alsk::exec::StaticPool, GRASPxELS>();
|
||||
graspEls.state.context.seed = args.seed;
|
||||
graspEls.executor.cores = NTHREADS;
|
||||
graspEls.skeleton.task.task<0>() = rgreedy();
|
||||
graspEls.skeleton.task.task<1>().task<1>().n = ELS_ITER_MAX;
|
||||
graspEls.skeleton.task.task<1>().task<1>().task.n = ELS_GEN;
|
||||
graspEls.skeleton.n = GRASP_N;
|
||||
|
||||
return graspEls(p);
|
||||
}
|
||||
|
||||
tsp::Solution sk_par_dynamicpool(tsp::Problem const& p, RNG&, Arguments const& args) {
|
||||
auto graspEls = alsk::implement<alsk::exec::DynamicPool, GRASPxELS>();
|
||||
graspEls.state.context.seed = args.seed;
|
||||
graspEls.executor.cores = NTHREADS;
|
||||
graspEls.skeleton.task.task<0>() = rgreedy();
|
||||
graspEls.skeleton.task.task<1>().task<1>().n = ELS_ITER_MAX;
|
||||
graspEls.skeleton.task.task<1>().task<1>().task.n = ELS_GEN;
|
||||
graspEls.skeleton.n = GRASP_N;
|
||||
|
||||
return graspEls(p);
|
||||
}
|
||||
|
||||
tsp::Solution sk_par_thread(tsp::Problem const& p, RNG&, Arguments const&) {
|
||||
auto graspEls = alsk::implement<alsk::exec::StaticThread, GRASPxELS>();
|
||||
graspEls.executor.cores = NTHREADS;
|
||||
graspEls.skeleton.task.task<0>() = rgreedy();
|
||||
graspEls.skeleton.task.task<1>().task<1>().n = ELS_ITER_MAX;
|
||||
graspEls.skeleton.task.task<1>().task<1>().task.n = ELS_GEN;
|
||||
graspEls.skeleton.n = GRASP_N;
|
||||
|
||||
return graspEls(p);
|
||||
}
|
111
bench/graspels/tbb.cpp
Normal file
111
bench/graspels/tbb.cpp
Normal file
@ -0,0 +1,111 @@
|
||||
#ifdef WITH_TBB
|
||||
|
||||
#include <tbb/task_scheduler_init.h>
|
||||
#include <tbb/flow_graph.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "decl.h"
|
||||
|
||||
/* *** */
|
||||
/* TBB */
|
||||
|
||||
auto tbbElsInner(tsp::Solution const& solution, RNG& rng, std::size_t nCore) {
|
||||
tsp::Solution best;
|
||||
std::vector<tsp::Solution> solutions(ELS_GEN);
|
||||
|
||||
/* repeatability at loop level */
|
||||
std::vector<RNG> rngs(ELS_GEN);
|
||||
for(std::size_t i = 0; i < ELS_GEN; ++i)
|
||||
rngs[i].seed(rng());
|
||||
/* ***** */
|
||||
|
||||
using ElsGenP = std::tuple<tsp::Solution const*, RNG*, tsp::Solution*>;
|
||||
using ElsGenR = std::tuple<tsp::Solution, tsp::Solution*>;
|
||||
|
||||
tbb::flow::graph g;
|
||||
tbb::flow::function_node<ElsGenP, ElsGenR> fElsGen(g, nCore,
|
||||
[](ElsGenP t) { return std::make_tuple(hwElsGen(*std::get<0>(t), *std::get<1>(t)), std::get<2>(t)); }
|
||||
);
|
||||
tbb::flow::function_node<ElsGenR, bool> fSelectMin(g, nCore,
|
||||
[](ElsGenR t) { *std::get<1>(t) = (selectMin(std::get<0>(t), *std::get<1>(t))); return true; }
|
||||
);
|
||||
|
||||
tbb::flow::make_edge(fElsGen, fSelectMin);
|
||||
|
||||
if(ELS_GEN)
|
||||
solutions[0] = hwElsGen(solution, rngs[0]);
|
||||
for(std::size_t i = 1; i < ELS_GEN; ++i)
|
||||
fElsGen.try_put(std::make_tuple(&solution, &rngs[i], &solutions[i]));
|
||||
|
||||
g.wait_for_all();
|
||||
|
||||
best = *std::min_element(std::begin(solutions), std::end(solutions));
|
||||
return best;
|
||||
}
|
||||
|
||||
auto tbbEls(tsp::Solution const& solution, RNG& rng,std::size_t nCore) {
|
||||
tsp::Solution best = Descent{}(solution);
|
||||
|
||||
for(std::size_t i = 0; i < ELS_ITER_MAX; ++i) {
|
||||
tsp::Solution current = tbbElsInner(best, rng, nCore);
|
||||
best = selectMin(std::move(best), std::move(current));
|
||||
}
|
||||
|
||||
return best;
|
||||
}
|
||||
|
||||
auto tbbGraspGen(tsp::Problem const& problem, RNG& rng, std::size_t nCore) {
|
||||
return tbbEls(rgreedy()(problem, rng), rng, nCore);
|
||||
}
|
||||
|
||||
template<std::size_t K>
|
||||
tsp::Solution tbbGraspElsPar(tsp::Problem const& problem, RNG& rng) {
|
||||
tsp::Solution best;
|
||||
std::vector<tsp::Solution> solutions(GRASP_N);
|
||||
|
||||
tbb::task_scheduler_init init(K);
|
||||
|
||||
/* repeatability at loop level */
|
||||
std::vector<RNG> rngs(GRASP_N);
|
||||
for(std::size_t i = 0; i < GRASP_N; ++i)
|
||||
rngs[i].seed(rng());
|
||||
/* ***** */
|
||||
|
||||
using GraspGenP = std::tuple<tsp::Problem const*, RNG*, unsigned long, tsp::Solution*>;
|
||||
using GraspGenR = std::tuple<tsp::Solution, tsp::Solution*>;
|
||||
|
||||
tbb::flow::graph g;
|
||||
tbb::flow::function_node<GraspGenP, GraspGenR> fGraspGen(g, K,
|
||||
[](GraspGenP t) { return std::make_tuple(tbbGraspGen(*std::get<0>(t), *std::get<1>(t), std::get<2>(t)), std::get<3>(t)); }
|
||||
);
|
||||
tbb::flow::function_node<GraspGenR, bool> fSelectMin(g, K,
|
||||
[](GraspGenR t) { *std::get<1>(t) = (selectMin(std::get<0>(t), *std::get<1>(t))); return true; }
|
||||
);
|
||||
|
||||
tbb::flow::make_edge(fGraspGen, fSelectMin);
|
||||
|
||||
for(std::size_t i = 0; i < GRASP_N; ++i)
|
||||
fGraspGen.try_put(std::make_tuple(&problem, &rngs[i], K, &solutions[i]));
|
||||
|
||||
g.wait_for_all();
|
||||
|
||||
/* Selection */
|
||||
best = *std::min_element(std::begin(solutions), std::end(solutions));
|
||||
|
||||
return best;
|
||||
}
|
||||
|
||||
tsp::Solution tbb_par(tsp::Problem const& p, RNG& rng, Arguments const&) {
|
||||
return tbbGraspElsPar<NTHREADS>(p, rng);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#include "common.h"
|
||||
|
||||
tsp::Solution tbb_par(tsp::Problem const&, RNG&, Arguments const&) {
|
||||
std::clog << "must compile with -ltbb -DWITH_TBB to enable TBB\n";
|
||||
return {};
|
||||
}
|
||||
|
||||
#endif
|
390
celero/celero/Archive.cpp
Normal file
390
celero/celero/Archive.cpp
Normal file
@ -0,0 +1,390 @@
|
||||
///
|
||||
/// \author John Farrier
|
||||
///
|
||||
/// \copyright Copyright 2015, 2016, 2017, 2018 John Farrier
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
|
||||
#include <assert.h>
|
||||
#include <celero/Archive.h>
|
||||
#include <celero/Benchmark.h>
|
||||
#include <celero/FileReader.h>
|
||||
#include <celero/PimplImpl.h>
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
using namespace celero;
|
||||
|
||||
///
|
||||
/// Structure to assist with archiving data during runtime and to a file.
|
||||
///
|
||||
struct ArchiveEntry
|
||||
{
|
||||
ArchiveEntry() :
|
||||
GroupName(),
|
||||
RunName(),
|
||||
ExperimentValue(0),
|
||||
ExperimentValueScale(0),
|
||||
FirstRanDate(0),
|
||||
TotalSamplesCollected(0),
|
||||
AverageBaseline(0),
|
||||
MinBaseline(0),
|
||||
MinBaseline_TimeSinceEpoch(0),
|
||||
MinStats(),
|
||||
MaxBaseline(0),
|
||||
MaxBaseline_TimeSinceEpoch(0),
|
||||
MaxStats(),
|
||||
CurrentBaseline(0),
|
||||
CurrentBaseline_TimeSinceEpoch(0),
|
||||
CurrentStats(),
|
||||
Failure(false)
|
||||
{
|
||||
}
|
||||
|
||||
static void WriteHeader(std::ostream& str)
|
||||
{
|
||||
str << "GroupName,RunName,Failure,ExperimentValue,ExperimentValueScale,FirstRanDate,TotalSamplesCollected,AverageBaseline,";
|
||||
str << "MinBaseline,MinBaselineTimeSinceEpoch,";
|
||||
str << "MinStatSize,MinStatMean,MinStatVariance,MinStatStandardDeviation,MinStatSkewness,MinStatKurtosis,";
|
||||
str << "MinStatMin,MinStatMax,";
|
||||
str << "MaxBaseline,MaxBaselineTimeSinceEpoch,";
|
||||
str << "MaxStatSize,MaxStatMean,MaxStatVariance,MaxStatStandardDeviation,MaxStatSkewness,MaxStatKurtosis,";
|
||||
str << "MaxStatMin,MaxStatMax,";
|
||||
str << "CurrentBaseline,CurrentBaselineTimeSinceEpoch,";
|
||||
str << "CurrentStatSize,CurrentStatMean,CurrentStatVariance,CurrentStatStandardDeviation,CurrentStatSkewness,CurrentStatKurtosis,";
|
||||
str << "CurrentStatMin,CurrentStatMax" << std::endl;
|
||||
}
|
||||
|
||||
struct Stat
|
||||
{
|
||||
Stat() : Size(0), Mean(0), Variance(0), StandardDeviation(0), Skewness(0), Kurtosis(0), Min(0), Max(0)
|
||||
{
|
||||
}
|
||||
|
||||
Stat& operator=(const celero::Statistics<int64_t>& s)
|
||||
{
|
||||
this->Size = s.getSize();
|
||||
this->Mean = s.getMean();
|
||||
this->Variance = s.getVariance();
|
||||
this->StandardDeviation = s.getStandardDeviation();
|
||||
this->Skewness = s.getSkewness();
|
||||
this->Kurtosis = s.getKurtosis();
|
||||
this->Min = s.getMin();
|
||||
this->Max = s.getMax();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
uint64_t Size;
|
||||
double Mean;
|
||||
double Variance;
|
||||
double StandardDeviation;
|
||||
double Skewness;
|
||||
double Kurtosis;
|
||||
uint64_t Min;
|
||||
uint64_t Max;
|
||||
};
|
||||
|
||||
std::string GroupName;
|
||||
std::string RunName;
|
||||
|
||||
/// The data set size, if one was specified.
|
||||
int64_t ExperimentValue;
|
||||
double ExperimentValueScale;
|
||||
|
||||
uint64_t FirstRanDate;
|
||||
uint32_t TotalSamplesCollected;
|
||||
|
||||
double AverageBaseline;
|
||||
|
||||
double MinBaseline;
|
||||
uint64_t MinBaseline_TimeSinceEpoch;
|
||||
Stat MinStats;
|
||||
|
||||
double MaxBaseline;
|
||||
uint64_t MaxBaseline_TimeSinceEpoch;
|
||||
Stat MaxStats;
|
||||
|
||||
double CurrentBaseline;
|
||||
uint64_t CurrentBaseline_TimeSinceEpoch;
|
||||
Stat CurrentStats;
|
||||
|
||||
bool Failure;
|
||||
};
|
||||
|
||||
///
|
||||
/// Overload operator<< to allow for easy output of result data to a human-readable text file.
|
||||
///
|
||||
std::ostream& operator<<(std::ostream& str, ArchiveEntry::Stat const& data)
|
||||
{
|
||||
str << data.Size << ",";
|
||||
str << data.Mean << ",";
|
||||
str << data.Variance << ",";
|
||||
str << data.StandardDeviation << ",";
|
||||
str << data.Skewness << ",";
|
||||
str << data.Kurtosis << ",";
|
||||
str << data.Min << ",";
|
||||
str << data.Max;
|
||||
return str;
|
||||
}
|
||||
|
||||
///
|
||||
/// Overload operator<< to allow for easy output of result data to a human-readable text file.
|
||||
///
|
||||
std::ostream& operator<<(std::ostream& str, ArchiveEntry const& data)
|
||||
{
|
||||
str << data.GroupName << ",";
|
||||
str << data.RunName << ",";
|
||||
str << data.Failure << ",";
|
||||
str << data.ExperimentValue << ",";
|
||||
str << data.ExperimentValueScale << ",";
|
||||
str << data.FirstRanDate << ",";
|
||||
str << data.TotalSamplesCollected << ",";
|
||||
str << data.AverageBaseline << ",";
|
||||
str << data.MinBaseline << ",";
|
||||
str << data.MinBaseline_TimeSinceEpoch << ",";
|
||||
str << data.MinStats << ",";
|
||||
str << data.MaxBaseline << ",";
|
||||
str << data.MaxBaseline_TimeSinceEpoch << ",";
|
||||
str << data.MaxStats << ",";
|
||||
str << data.CurrentBaseline << ",";
|
||||
str << data.CurrentBaseline_TimeSinceEpoch << ",";
|
||||
str << data.CurrentStats << std::endl;
|
||||
return str;
|
||||
}
|
||||
|
||||
///
|
||||
/// Overload operator>> to allow for easy input of result data from a text file.
|
||||
///
|
||||
std::istream& operator>>(std::istream& str, ArchiveEntry::Stat& data)
|
||||
{
|
||||
// Use FieldReader to classify commas as whitespace.
|
||||
str.imbue(std::locale(std::locale(), new celero::FieldReader));
|
||||
|
||||
str >> data.Size;
|
||||
str >> data.Mean;
|
||||
str >> data.Variance;
|
||||
str >> data.StandardDeviation;
|
||||
str >> data.Skewness;
|
||||
str >> data.Kurtosis;
|
||||
str >> data.Min;
|
||||
str >> data.Max;
|
||||
return str;
|
||||
}
|
||||
|
||||
///
|
||||
/// Overload operator>> to allow for easy input of result data from a text file.
|
||||
///
|
||||
std::istream& operator>>(std::istream& str, ArchiveEntry& data)
|
||||
{
|
||||
// Use FieldReader to classify commas as whitespace.
|
||||
str.imbue(std::locale(std::locale(), new celero::FieldReader));
|
||||
|
||||
str >> data.GroupName;
|
||||
str >> data.RunName;
|
||||
str >> data.Failure;
|
||||
str >> data.ExperimentValue;
|
||||
str >> data.ExperimentValueScale;
|
||||
str >> data.FirstRanDate;
|
||||
str >> data.TotalSamplesCollected;
|
||||
str >> data.AverageBaseline;
|
||||
str >> data.MinBaseline;
|
||||
str >> data.MinBaseline_TimeSinceEpoch;
|
||||
str >> data.MinStats;
|
||||
str >> data.MaxBaseline;
|
||||
str >> data.MaxBaseline_TimeSinceEpoch;
|
||||
str >> data.MaxStats;
|
||||
str >> data.CurrentBaseline;
|
||||
str >> data.CurrentBaseline_TimeSinceEpoch;
|
||||
str >> data.CurrentStats;
|
||||
return str;
|
||||
}
|
||||
|
||||
///
|
||||
/// \class Impl
|
||||
///
|
||||
class celero::Archive::Impl
|
||||
{
|
||||
public:
|
||||
Impl() : results(), fileName()
|
||||
{
|
||||
}
|
||||
|
||||
/// Return milliseconds since epoch.
|
||||
uint64_t now() const
|
||||
{
|
||||
return static_cast<uint64_t>(
|
||||
std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count());
|
||||
}
|
||||
|
||||
void readExistingResults()
|
||||
{
|
||||
// Read in existing results?
|
||||
std::ifstream is;
|
||||
is.open(this->fileName, std::fstream::in);
|
||||
|
||||
if((is.is_open() == true) && (is.good() == true) && (is.fail() == false))
|
||||
{
|
||||
// Throw away the header.
|
||||
is.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
|
||||
|
||||
// Read in existing results.
|
||||
while((is.eof() == false) && (is.tellg() >= 0))
|
||||
{
|
||||
ArchiveEntry r;
|
||||
is >> r;
|
||||
|
||||
if(r.GroupName.empty() == false)
|
||||
{
|
||||
this->results.push_back(r);
|
||||
}
|
||||
}
|
||||
|
||||
// Close the file for reading.
|
||||
is.close();
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<ArchiveEntry> results;
|
||||
std::string fileName;
|
||||
};
|
||||
|
||||
Archive::Archive() : pimpl()
|
||||
{
|
||||
}
|
||||
|
||||
Archive::~Archive()
|
||||
{
|
||||
}
|
||||
|
||||
Archive& Archive::Instance()
|
||||
{
|
||||
static Archive singleton;
|
||||
return singleton;
|
||||
}
|
||||
|
||||
void Archive::setFileName(const std::string& x)
|
||||
{
|
||||
assert(x.empty() == false);
|
||||
this->pimpl->fileName = x;
|
||||
this->pimpl->readExistingResults();
|
||||
}
|
||||
|
||||
void Archive::add(std::shared_ptr<celero::ExperimentResult> x)
|
||||
{
|
||||
const auto found = std::find_if(std::begin(this->pimpl->results), std::end(this->pimpl->results), [x](const ArchiveEntry& r) -> bool {
|
||||
return (r.GroupName == x->getExperiment()->getBenchmark()->getName()) && (r.RunName == x->getExperiment()->getName())
|
||||
&& (r.ExperimentValue == x->getProblemSpaceValue());
|
||||
});
|
||||
|
||||
if(found != std::end(this->pimpl->results))
|
||||
{
|
||||
if(x->getFailure() == true)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
found->CurrentBaseline = x->getBaselineMeasurement();
|
||||
found->CurrentBaseline_TimeSinceEpoch = this->pimpl->now();
|
||||
found->CurrentStats = *x->getTimeStatistics();
|
||||
|
||||
if(found->Failure || found->CurrentBaseline <= found->MinBaseline)
|
||||
{
|
||||
found->MinBaseline = found->CurrentBaseline;
|
||||
found->MinBaseline_TimeSinceEpoch = found->CurrentBaseline_TimeSinceEpoch;
|
||||
found->MinStats = found->CurrentStats;
|
||||
}
|
||||
|
||||
if(found->Failure || found->CurrentBaseline >= found->MaxBaseline)
|
||||
{
|
||||
found->MaxBaseline = found->CurrentBaseline;
|
||||
found->MaxBaseline_TimeSinceEpoch = found->CurrentBaseline_TimeSinceEpoch;
|
||||
found->MaxStats = found->CurrentStats;
|
||||
}
|
||||
|
||||
// This is not good IEEE math.
|
||||
if(found->Failure == false)
|
||||
{
|
||||
found->AverageBaseline =
|
||||
((found->AverageBaseline * found->TotalSamplesCollected) + found->CurrentBaseline) / (found->TotalSamplesCollected + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
found->AverageBaseline = found->CurrentBaseline;
|
||||
}
|
||||
|
||||
found->TotalSamplesCollected++;
|
||||
}
|
||||
else
|
||||
{
|
||||
ArchiveEntry r;
|
||||
|
||||
r.GroupName = x->getExperiment()->getBenchmark()->getName();
|
||||
r.RunName = x->getExperiment()->getName();
|
||||
r.Failure = x->getFailure();
|
||||
r.FirstRanDate = this->pimpl->now();
|
||||
r.AverageBaseline = x->getBaselineMeasurement();
|
||||
r.ExperimentValue = x->getProblemSpaceValue();
|
||||
r.ExperimentValueScale = x->getProblemSpaceValueScale();
|
||||
r.TotalSamplesCollected = x->getFailure() ? 0 : 1;
|
||||
|
||||
r.CurrentBaseline = x->getBaselineMeasurement();
|
||||
r.CurrentBaseline_TimeSinceEpoch = r.FirstRanDate;
|
||||
r.CurrentStats = *x->getTimeStatistics();
|
||||
|
||||
r.MaxBaseline = x->getBaselineMeasurement();
|
||||
r.MaxBaseline_TimeSinceEpoch = r.FirstRanDate;
|
||||
r.MaxStats = *x->getTimeStatistics();
|
||||
|
||||
r.MinBaseline = x->getBaselineMeasurement();
|
||||
r.MinBaseline_TimeSinceEpoch = r.FirstRanDate;
|
||||
r.MinStats = *x->getTimeStatistics();
|
||||
|
||||
this->pimpl->results.push_back(r);
|
||||
}
|
||||
|
||||
this->save();
|
||||
}
|
||||
|
||||
void Archive::save()
|
||||
{
|
||||
if(this->pimpl->fileName.empty() == false)
|
||||
{
|
||||
// Get ready to write out new results.
|
||||
// We will write all known results every time, replacing file contents.
|
||||
std::ofstream os;
|
||||
os.open(this->pimpl->fileName.c_str(), std::fstream::out);
|
||||
|
||||
if(os.is_open() == true)
|
||||
{
|
||||
ArchiveEntry::WriteHeader(os);
|
||||
|
||||
for(auto& i : this->pimpl->results)
|
||||
{
|
||||
os << i;
|
||||
}
|
||||
|
||||
os.flush();
|
||||
os.close();
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "Celero: Could not open result output file: \"" << this->pimpl->fileName << "\"" << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
102
celero/celero/Archive.h
Normal file
102
celero/celero/Archive.h
Normal file
@ -0,0 +1,102 @@
|
||||
#ifndef H_CELERO_ARCHIVE_H
|
||||
#define H_CELERO_ARCHIVE_H
|
||||
|
||||
///
|
||||
/// \author John Farrier
|
||||
///
|
||||
/// \copyright Copyright 2015, 2016, 2017, 2018 John Farrier
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
|
||||
#include <celero/Experiment.h>
|
||||
#include <celero/ExperimentResult.h>
|
||||
#include <string>
|
||||
|
||||
namespace celero
|
||||
{
|
||||
///
|
||||
/// \class Archive
|
||||
///
|
||||
/// \author John Farrier
|
||||
///
|
||||
class CELERO_EXPORT Archive
|
||||
{
|
||||
public:
|
||||
///
|
||||
/// Singleton
|
||||
///
|
||||
static Archive& Instance();
|
||||
|
||||
///
|
||||
/// Specify a file name for a results output file.
|
||||
///
|
||||
/// \param x The name of the output file in which to store Celero's results.
|
||||
///
|
||||
void setFileName(const std::string& x);
|
||||
|
||||
///
|
||||
/// Adds or updates a result which will be saved to a results archive file.
|
||||
///
|
||||
/// This should re-save on every new result so that the output can be monitored externally.
|
||||
///
|
||||
void add(std::shared_ptr<celero::ExperimentResult> x);
|
||||
|
||||
///
|
||||
/// Saves all current results to a results archive file.
|
||||
///
|
||||
/// Will overwrite all existing data and refresh with new data.
|
||||
///
|
||||
void save();
|
||||
|
||||
private:
|
||||
///
|
||||
/// Default Constructor
|
||||
///
|
||||
Archive();
|
||||
|
||||
///
|
||||
/// Non-copyable.
|
||||
/// Visual studio 2012 does not support "delete" here.
|
||||
///
|
||||
Archive(Archive&)
|
||||
{
|
||||
}
|
||||
|
||||
///
|
||||
/// Default Destructor
|
||||
///
|
||||
~Archive();
|
||||
|
||||
///
|
||||
/// Non-assignable.
|
||||
/// Visual studio 2012 does not support "delete" here.
|
||||
///
|
||||
Archive& operator=(const Archive&)
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Pimpl Idiom
|
||||
///
|
||||
class Impl;
|
||||
|
||||
///
|
||||
/// \brief Pimpl Idiom
|
||||
///
|
||||
Pimpl<Impl> pimpl;
|
||||
};
|
||||
} // namespace celero
|
||||
|
||||
#endif
|
120
celero/celero/Benchmark.cpp
Normal file
120
celero/celero/Benchmark.cpp
Normal file
@ -0,0 +1,120 @@
|
||||
///
|
||||
/// \author John Farrier
|
||||
///
|
||||
/// \copyright Copyright 2015, 2016, 2017, 2018 John Farrier
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
|
||||
#include <celero/Benchmark.h>
|
||||
#include <celero/PimplImpl.h>
|
||||
#include <celero/Utilities.h>
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
|
||||
using namespace celero;
|
||||
|
||||
class Benchmark::Impl
|
||||
{
|
||||
public:
|
||||
Impl() : stats(), name(), baseline(), experiments()
|
||||
{
|
||||
}
|
||||
|
||||
Impl(const std::string& x) : stats(), name(x), baseline(), experiments()
|
||||
{
|
||||
}
|
||||
|
||||
Impl(const Benchmark& other) : stats(), name(other.pimpl->name), baseline(), experiments()
|
||||
{
|
||||
}
|
||||
|
||||
void copy(const Benchmark& other)
|
||||
{
|
||||
stats = other.pimpl->stats;
|
||||
name = other.pimpl->name;
|
||||
baseline = other.pimpl->baseline;
|
||||
experiments = other.pimpl->experiments;
|
||||
}
|
||||
|
||||
Statistics<int64_t> stats;
|
||||
|
||||
/// Group name
|
||||
std::string name;
|
||||
|
||||
std::shared_ptr<Experiment> baseline;
|
||||
std::vector<std::shared_ptr<Experiment>> experiments;
|
||||
};
|
||||
|
||||
Benchmark::Benchmark() : pimpl()
|
||||
{
|
||||
}
|
||||
|
||||
Benchmark::Benchmark(const std::string& name) : pimpl(name)
|
||||
{
|
||||
}
|
||||
|
||||
Benchmark::Benchmark(const Benchmark& other) : pimpl(other)
|
||||
{
|
||||
}
|
||||
|
||||
Benchmark::~Benchmark()
|
||||
{
|
||||
}
|
||||
|
||||
Benchmark& Benchmark::operator=(const Benchmark& other)
|
||||
{
|
||||
if(&other != this)
|
||||
{
|
||||
this->pimpl->copy(other);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::string Benchmark::getName() const
|
||||
{
|
||||
return this->pimpl->name;
|
||||
}
|
||||
|
||||
void Benchmark::setBaseline(std::shared_ptr<Experiment> x)
|
||||
{
|
||||
this->pimpl->baseline = x;
|
||||
}
|
||||
|
||||
std::shared_ptr<Experiment> Benchmark::getBaseline() const
|
||||
{
|
||||
return this->pimpl->baseline;
|
||||
}
|
||||
|
||||
void Benchmark::addExperiment(std::shared_ptr<Experiment> x)
|
||||
{
|
||||
this->pimpl->experiments.push_back(x);
|
||||
}
|
||||
|
||||
std::shared_ptr<Experiment> Benchmark::getExperiment(size_t x)
|
||||
{
|
||||
// This is unsafe, but not user code. I'll accept the risk.
|
||||
return this->pimpl->experiments[x];
|
||||
}
|
||||
|
||||
std::shared_ptr<Experiment> Benchmark::getExperiment(const std::string& x)
|
||||
{
|
||||
return *std::find_if(std::begin(this->pimpl->experiments), std::end(this->pimpl->experiments),
|
||||
[x](decltype(*std::begin(this->pimpl->experiments)) i) -> bool { return (i->getName() == x); });
|
||||
}
|
||||
|
||||
size_t Benchmark::getExperimentSize() const
|
||||
{
|
||||
return this->pimpl->experiments.size();
|
||||
}
|
112
celero/celero/Benchmark.h
Normal file
112
celero/celero/Benchmark.h
Normal file
@ -0,0 +1,112 @@
|
||||
#ifndef H_CELERO_BENCHMARK_H
|
||||
#define H_CELERO_BENCHMARK_H
|
||||
|
||||
///
|
||||
/// \author John Farrier
|
||||
///
|
||||
/// \copyright Copyright 2015, 2016, 2017, 2018 John Farrier
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
|
||||
#include <celero/Experiment.h>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace celero
|
||||
{
|
||||
///
|
||||
/// \class Benchmark
|
||||
///
|
||||
/// \author John Farrier
|
||||
///
|
||||
class CELERO_EXPORT Benchmark
|
||||
{
|
||||
public:
|
||||
///
|
||||
/// \brief Default constructor
|
||||
///
|
||||
Benchmark();
|
||||
|
||||
///
|
||||
/// \brief Overloaded constructor.
|
||||
///
|
||||
/// \param name Name of the test group.
|
||||
///
|
||||
Benchmark(const std::string& name);
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Benchmark(const Benchmark& other);
|
||||
|
||||
///
|
||||
/// \brief Default destructor.
|
||||
///
|
||||
~Benchmark();
|
||||
|
||||
///
|
||||
/// Assignment Operator
|
||||
///
|
||||
Benchmark& operator=(const Benchmark& other);
|
||||
|
||||
///
|
||||
/// The name to group all experiment under.
|
||||
///
|
||||
std::string getName() const;
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
void setBaseline(std::shared_ptr<Experiment> x);
|
||||
|
||||
///
|
||||
/// Gets the baseline case associated this benchmark.
|
||||
///
|
||||
std::shared_ptr<Experiment> getBaseline() const;
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
void addExperiment(std::shared_ptr<Experiment> x);
|
||||
|
||||
///
|
||||
/// Gets the test case associated with the given experiment index.
|
||||
///
|
||||
std::shared_ptr<Experiment> getExperiment(size_t experimentIndex);
|
||||
|
||||
///
|
||||
/// Gets the test case associated with the given experiment name.
|
||||
///
|
||||
std::shared_ptr<Experiment> getExperiment(const std::string& experimentName);
|
||||
|
||||
///
|
||||
/// Returns the total number of experiments per benchmark.
|
||||
///
|
||||
size_t getExperimentSize() const;
|
||||
|
||||
private:
|
||||
///
|
||||
/// \brief Pimpl Idiom
|
||||
///
|
||||
class Impl;
|
||||
|
||||
///
|
||||
/// \brief Pimpl Idiom
|
||||
///
|
||||
Pimpl<Impl> pimpl;
|
||||
};
|
||||
} // namespace celero
|
||||
|
||||
#endif
|
52
celero/celero/Callbacks.cpp
Normal file
52
celero/celero/Callbacks.cpp
Normal file
@ -0,0 +1,52 @@
|
||||
///
|
||||
/// \author John Farrier
|
||||
///
|
||||
/// \copyright Copyright 2015, 2016, 2017, 2018 John Farrier
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
|
||||
#include <celero/Callbacks.h>
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
using namespace celero;
|
||||
|
||||
std::vector<std::function<void(std::shared_ptr<Experiment>)>> ExperimentFunctions;
|
||||
std::vector<std::function<void(std::shared_ptr<celero::ExperimentResult>)>> ExperimentResultFunctions;
|
||||
|
||||
void celero::impl::ExperimentComplete(std::shared_ptr<Experiment> x)
|
||||
{
|
||||
for(auto& i : ExperimentFunctions)
|
||||
{
|
||||
i(x);
|
||||
}
|
||||
}
|
||||
|
||||
void celero::impl::ExperimentResultComplete(std::shared_ptr<celero::ExperimentResult> x)
|
||||
{
|
||||
for(auto& i : ExperimentResultFunctions)
|
||||
{
|
||||
i(x);
|
||||
}
|
||||
}
|
||||
|
||||
void celero::AddExperimentCompleteFunction(std::function<void(std::shared_ptr<Experiment>)> x)
|
||||
{
|
||||
ExperimentFunctions.push_back(x);
|
||||
}
|
||||
|
||||
void celero::AddExperimentResultCompleteFunction(std::function<void(std::shared_ptr<celero::ExperimentResult>)> x)
|
||||
{
|
||||
ExperimentResultFunctions.push_back(x);
|
||||
}
|
65
celero/celero/Callbacks.h
Normal file
65
celero/celero/Callbacks.h
Normal file
@ -0,0 +1,65 @@
|
||||
#ifndef H_CELERO_CALLBACKS_H
|
||||
#define H_CELERO_CALLBACKS_H
|
||||
|
||||
///
|
||||
/// \namespace celero
|
||||
///
|
||||
/// \author John Farrier
|
||||
///
|
||||
/// \copyright Copyright 2015, 2016, 2017, 2018 John Farrier
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
/// Ideas from Nick Brunn's Hayai (https://github.com/nickbruun/hayai) were used and I likely owe him a beer.
|
||||
///
|
||||
/// Special thanks to the band "3" for providing the development soundtrack.
|
||||
///
|
||||
/// "Iterations" refers to how many loops of the test function are measured as a time.
|
||||
/// For very fast code, many iterations would help amoratize measurement error.
|
||||
///
|
||||
/// "Samples" refers to how many sets of "iterations" will be performed. Each "sample" is
|
||||
/// a single measurement. Set to 0 to have Celero decide how many samples are required
|
||||
/// for a minimally significant answer.
|
||||
///
|
||||
/// It is highly encouraged to only run this code compiled in a "Release" mode to use all available optimizations.
|
||||
///
|
||||
|
||||
#include <celero/Experiment.h>
|
||||
#include <celero/Export.h>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
namespace celero
|
||||
{
|
||||
///
|
||||
/// \brief Add a function to call when a experiment is completed.
|
||||
///
|
||||
/// This will be called at the end of a complete experiment (benchmark + experiment results.)
|
||||
///
|
||||
CELERO_EXPORT void AddExperimentCompleteFunction(std::function<void(std::shared_ptr<celero::Experiment>)> x);
|
||||
|
||||
///
|
||||
/// \brief Add a function to call when a experiment is completed.
|
||||
///
|
||||
/// This will be called at the end of every benchmark or user experiment upon completion.
|
||||
///
|
||||
CELERO_EXPORT void AddExperimentResultCompleteFunction(std::function<void(std::shared_ptr<celero::ExperimentResult>)> x);
|
||||
|
||||
namespace impl
|
||||
{
|
||||
void ExperimentComplete(std::shared_ptr<Experiment> x);
|
||||
void ExperimentResultComplete(std::shared_ptr<celero::ExperimentResult> x);
|
||||
} // namespace impl
|
||||
} // namespace celero
|
||||
|
||||
#endif
|
256
celero/celero/Celero.cpp
Normal file
256
celero/celero/Celero.cpp
Normal file
@ -0,0 +1,256 @@
|
||||
///
|
||||
/// \author John Farrier
|
||||
///
|
||||
/// \copyright Copyright 2015, 2016, 2017, 2018 John Farrier
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
|
||||
#include <celero/Archive.h>
|
||||
#include <celero/Benchmark.h>
|
||||
#include <celero/Callbacks.h>
|
||||
#include <celero/Celero.h>
|
||||
#include <celero/CommandLine.h>
|
||||
#include <celero/Console.h>
|
||||
#include <celero/Distribution.h>
|
||||
#include <celero/Exceptions.h>
|
||||
#include <celero/Executor.h>
|
||||
#include <celero/JUnit.h>
|
||||
#include <celero/Print.h>
|
||||
#include <celero/ResultTable.h>
|
||||
#include <celero/TestVector.h>
|
||||
#include <celero/UserDefinedMeasurement.h>
|
||||
#include <celero/Utilities.h>
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <set>
|
||||
|
||||
using namespace celero;
|
||||
|
||||
std::shared_ptr<celero::Benchmark> celero::RegisterTest(const char* groupName, const char* benchmarkName, const uint64_t samples,
|
||||
const uint64_t iterations, const uint64_t threads,
|
||||
std::shared_ptr<celero::Factory> experimentFactory, const double target)
|
||||
{
|
||||
auto bm = celero::TestVector::Instance()[groupName];
|
||||
|
||||
if(bm == nullptr)
|
||||
{
|
||||
bm = std::make_shared<Benchmark>(groupName);
|
||||
celero::TestVector::Instance().push_back(bm);
|
||||
}
|
||||
|
||||
auto p = std::make_shared<Experiment>(bm);
|
||||
p->setIsBaselineCase(false);
|
||||
p->setName(benchmarkName);
|
||||
p->setSamples(samples);
|
||||
p->setIterations(iterations);
|
||||
p->setThreads(threads);
|
||||
p->setFactory(experimentFactory);
|
||||
p->setBaselineTarget(target);
|
||||
|
||||
bm->addExperiment(p);
|
||||
|
||||
return bm;
|
||||
}
|
||||
|
||||
std::shared_ptr<celero::Benchmark> celero::RegisterBaseline(const char* groupName, const char* benchmarkName, const uint64_t samples,
|
||||
const uint64_t iterations, const uint64_t threads,
|
||||
std::shared_ptr<celero::Factory> experimentFactory)
|
||||
{
|
||||
auto bm = celero::TestVector::Instance()[groupName];
|
||||
|
||||
if(bm == nullptr)
|
||||
{
|
||||
bm = std::make_shared<Benchmark>(groupName);
|
||||
celero::TestVector::Instance().push_back(bm);
|
||||
}
|
||||
|
||||
auto p = std::make_shared<Experiment>(bm);
|
||||
p->setIsBaselineCase(true);
|
||||
p->setName(benchmarkName);
|
||||
p->setSamples(samples);
|
||||
p->setIterations(iterations);
|
||||
p->setThreads(threads);
|
||||
p->setFactory(experimentFactory);
|
||||
p->setBaselineTarget(1.0);
|
||||
|
||||
bm->setBaseline(p);
|
||||
|
||||
return bm;
|
||||
}
|
||||
|
||||
void celero::Run(int argc, char** argv)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
std::cout << "Celero is running in Debug. Results are for debugging only as any measurements made while in Debug are likely not representative "
|
||||
"of non-debug results."
|
||||
<< std::endl
|
||||
<< std::endl;
|
||||
#endif
|
||||
|
||||
cmdline::parser args;
|
||||
args.add("list", 'l', "Prints a list of all available benchmarks.");
|
||||
args.add<std::string>("group", 'g', "Runs a specific group of benchmarks.", false, "");
|
||||
args.add<std::string>("outputTable", 't', "Saves a results table to the named file.", false, "");
|
||||
args.add<std::string>("junit", 'j', "Saves a JUnit XML-formatted file to the named file.", false, "");
|
||||
args.add<std::string>("archive", 'a', "Saves or updates a result archive file.", false, "");
|
||||
args.add<uint64_t>("distribution", 'd', "Builds a file to help characterize the distribution of measurements and exits.", false, 0);
|
||||
args.add<bool>("catchExceptions", 'e', "Allows Celero to catch exceptions and continue processing following benchmarks.", false, true);
|
||||
args.parse_check(argc, argv);
|
||||
|
||||
if(args.exist("list") == true)
|
||||
{
|
||||
auto& tests = celero::TestVector::Instance();
|
||||
std::vector<std::string> testNames;
|
||||
|
||||
for(auto i = size_t(0); i < tests.size(); i++)
|
||||
{
|
||||
auto bm = celero::TestVector::Instance()[i];
|
||||
testNames.push_back(bm->getName());
|
||||
}
|
||||
|
||||
std::sort(std::begin(testNames), std::end(testNames));
|
||||
|
||||
std::cout << "Avaliable tests:" << std::endl;
|
||||
for(auto i : testNames)
|
||||
{
|
||||
std::cout << "\t" << i << std::endl;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Initial output
|
||||
std::cout << "Celero" << std::endl;
|
||||
|
||||
// Disable dynamic CPU frequency scaling
|
||||
celero::timer::CachePerformanceFrequency(false);
|
||||
|
||||
// Shall we build a distribution?
|
||||
auto intArgument = args.get<uint64_t>("distribution");
|
||||
if(intArgument > 0)
|
||||
{
|
||||
RunDistribution(intArgument);
|
||||
}
|
||||
|
||||
// Has a result output file been specified?
|
||||
auto mustCloseFile = false;
|
||||
auto argument = args.get<std::string>("outputTable");
|
||||
if(argument.empty() == false)
|
||||
{
|
||||
std::cout << "Writing results to: " << argument << std::endl;
|
||||
celero::ResultTable::Instance().setFileName(argument);
|
||||
|
||||
celero::AddExperimentResultCompleteFunction([](std::shared_ptr<celero::ExperimentResult> p) { celero::ResultTable::Instance().add(p); });
|
||||
mustCloseFile = true;
|
||||
}
|
||||
|
||||
// Has a result output file been specified?
|
||||
argument = args.get<std::string>("archive");
|
||||
if(argument.empty() == false)
|
||||
{
|
||||
std::cout << "Archiving results to: " << argument << std::endl;
|
||||
celero::Archive::Instance().setFileName(argument);
|
||||
|
||||
celero::AddExperimentResultCompleteFunction([](std::shared_ptr<celero::ExperimentResult> p) { celero::Archive::Instance().add(p); });
|
||||
}
|
||||
|
||||
// Has a JUnit output file been specified?
|
||||
argument = args.get<std::string>("junit");
|
||||
if(argument.empty() == false)
|
||||
{
|
||||
std::cout << "Writing JUnit results to: " << argument << std::endl;
|
||||
celero::JUnit::Instance().setFileName(argument);
|
||||
|
||||
celero::AddExperimentResultCompleteFunction([](std::shared_ptr<celero::ExperimentResult> p) { celero::JUnit::Instance().add(p); });
|
||||
}
|
||||
|
||||
// Has a flag to catch exceptions or not been specified?
|
||||
if(args.exist("catchExceptions") == true)
|
||||
{
|
||||
ExceptionSettings::SetCatchExceptions(args.get<bool>("catchExceptions"));
|
||||
}
|
||||
|
||||
// Has a run group been specified?
|
||||
argument = args.get<std::string>("group");
|
||||
|
||||
// Collect all user-defined fields
|
||||
std::set<std::string> userDefinedFields;
|
||||
auto collectFromBenchmark = [&](std::shared_ptr<Benchmark> bmark) {
|
||||
// Collect from baseline
|
||||
auto baselineExperiment = bmark->getBaseline();
|
||||
if(baselineExperiment != nullptr)
|
||||
{
|
||||
auto test = baselineExperiment->getFactory()->Create();
|
||||
UserDefinedMeasurementCollector udmCollector(test);
|
||||
for(const auto& fieldName : udmCollector.getFields(test))
|
||||
{
|
||||
userDefinedFields.insert(fieldName);
|
||||
}
|
||||
}
|
||||
|
||||
// Collect from all experiments
|
||||
const auto experimentSize = bmark->getExperimentSize();
|
||||
|
||||
for(size_t i = 0; i < experimentSize; i++)
|
||||
{
|
||||
auto e = bmark->getExperiment(i);
|
||||
assert(e != nullptr);
|
||||
|
||||
auto test = baselineExperiment->getFactory()->Create();
|
||||
UserDefinedMeasurementCollector udmCollector(test);
|
||||
for(const auto& fieldName : udmCollector.getFields(test))
|
||||
{
|
||||
userDefinedFields.insert(fieldName);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if(argument.empty() == false)
|
||||
{
|
||||
auto bmark = celero::TestVector::Instance()[argument];
|
||||
collectFromBenchmark(bmark);
|
||||
}
|
||||
else
|
||||
{
|
||||
for(size_t i = 0; i < celero::TestVector::Instance().size(); i++)
|
||||
{
|
||||
auto bmark = celero::TestVector::Instance()[i];
|
||||
collectFromBenchmark(bmark);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::string> userDefinedFieldsOrder(userDefinedFields.begin(), userDefinedFields.end());
|
||||
|
||||
Printer::get().initialize(userDefinedFieldsOrder);
|
||||
Printer::get().TableBanner();
|
||||
|
||||
if(argument.empty() == false)
|
||||
{
|
||||
executor::Run(argument);
|
||||
}
|
||||
else
|
||||
{
|
||||
executor::RunAll();
|
||||
}
|
||||
|
||||
if(mustCloseFile == true)
|
||||
{
|
||||
celero::ResultTable::Instance().closeFile();
|
||||
}
|
||||
|
||||
// Final output.
|
||||
std::cout << "Complete." << std::endl;
|
||||
}
|
315
celero/celero/Celero.h
Normal file
315
celero/celero/Celero.h
Normal file
@ -0,0 +1,315 @@
|
||||
#ifndef H_CELERO_CELERO_H
|
||||
#define H_CELERO_CELERO_H
|
||||
|
||||
///
|
||||
/// \namespace celero
|
||||
///
|
||||
/// \author John Farrier
|
||||
///
|
||||
/// \copyright Copyright 2015, 2016, 2017, 2018 John Farrier
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
/// Special thanks to the bands "3" and "Coheed and Cambria" for providing the development soundtrack.
|
||||
///
|
||||
/// "Iterations" refers to how many loops of the test function are measured as a time.
|
||||
/// For very fast code, many iterations would help amoratize measurement error.
|
||||
///
|
||||
/// "Samples" refers to how many sets of "Iterations" will be performed. Each "sample" is
|
||||
/// a single measurement.
|
||||
///
|
||||
/// It is highly encouraged to only run this code compiled in a "Release" mode to use all available optimizations.
|
||||
///
|
||||
|
||||
#ifdef WIN32
|
||||
#include <process.h>
|
||||
#endif
|
||||
|
||||
#include <celero/Benchmark.h>
|
||||
#include <celero/GenericFactory.h>
|
||||
#include <celero/TestFixture.h>
|
||||
#include <celero/ThreadTestFixture.h>
|
||||
#include <celero/UserDefinedMeasurementCollector.h>
|
||||
#include <celero/UserDefinedMeasurementTemplate.h>
|
||||
#include <celero/Utilities.h>
|
||||
|
||||
namespace celero
|
||||
{
|
||||
///
|
||||
/// \brief Adds a new test to the list of tests to be executed.
|
||||
///
|
||||
/// All tests must be registered prior to calling celer::Run().
|
||||
///
|
||||
/// \param groupName The name of the Test Group. Used for retrieving the associated baseline.
|
||||
/// \param benchmarkName A unique name for a specific test within a Test Group.
|
||||
/// \param samples The total number of times to execute the Test. (Each test contains iterations.)
|
||||
/// \param iterations The total number of iterations per Test.
|
||||
/// \param threads The total number of threads per Test sample.
|
||||
/// \param experimentFactory The factory implementation for the test.
|
||||
///
|
||||
/// \returns a pointer to a Benchmark instance representing the given test.
|
||||
///
|
||||
CELERO_EXPORT std::shared_ptr<Benchmark> RegisterTest(const char* groupName, const char* benchmarkName, const uint64_t samples,
|
||||
const uint64_t iterations, const uint64_t threads,
|
||||
std::shared_ptr<Factory> experimentFactory, const double target = -1);
|
||||
|
||||
///
|
||||
/// \brief Adds a new test baseline to the list of test baseliness to be executed.
|
||||
///
|
||||
/// All test baselines must be registered prior to calling celer::Run().
|
||||
///
|
||||
/// \param groupName The name of the Test Group that the baseline is associated with.
|
||||
/// \param benchmarkName A unique name for a specific test baseline within a Test Group.
|
||||
/// \param samples The total number of times to execute the Test baseline. (Each sample contains one or more iterations.)
|
||||
/// \param iterations The total number of iterations per Test baseline sample.
|
||||
/// \param threads The total number of threads per Test baseline.
|
||||
/// \param experimentFactory The factory implementation for the test baseline.
|
||||
///
|
||||
/// \returns a pointer to a Benchmark instance representing the given test.
|
||||
///
|
||||
CELERO_EXPORT std::shared_ptr<Benchmark> RegisterBaseline(const char* groupName, const char* benchmarkName, const uint64_t samples,
|
||||
const uint64_t iterations, const uint64_t threads,
|
||||
std::shared_ptr<Factory> experimentFactory);
|
||||
|
||||
///
|
||||
/// \brief Builds a distribution of total system measurement error.
|
||||
///
|
||||
/// The result vector contains microseconds for each trivial timer sample.
|
||||
/// The purpose is to be able to characterize the generic distribution of results
|
||||
/// on a given system.
|
||||
///
|
||||
/// This is just an attempt to characterize the distribution, not quantify it.
|
||||
///
|
||||
CELERO_EXPORT std::vector<uint64_t> BuildDistribution(uint64_t numberOfSamples, uint64_t iterationsPerSample);
|
||||
|
||||
///
|
||||
/// \brief The main test executor.
|
||||
///
|
||||
CELERO_EXPORT void Run(int argc, char** argv);
|
||||
} // namespace celero
|
||||
|
||||
///
|
||||
/// \define CELERO_MAIN
|
||||
///
|
||||
/// \brief A macro to build the most basic main() required to run the benchmark tests.
|
||||
///
|
||||
#define CELERO_MAIN \
|
||||
int main(int argc, char** argv) \
|
||||
{ \
|
||||
celero::Run(argc, argv); \
|
||||
return 0; \
|
||||
}
|
||||
|
||||
///
|
||||
/// \define BENCHMARK_CLASS_NAME
|
||||
///
|
||||
/// \brief A macro to build a class name based on the test groupo and benchmark names.
|
||||
///
|
||||
#define BENCHMARK_CLASS_NAME(groupName, benchmarkName) CeleroUserBenchmark##_##groupName##_##benchmarkName
|
||||
|
||||
///
|
||||
/// \define BENCHMARK_IMPL
|
||||
///
|
||||
/// A macro to create a class of a unique name which can be used to register and execute a benchmark test.
|
||||
///
|
||||
#define BENCHMARK_IMPL(groupName, benchmarkName, fixtureName, samples, iterations, threads) \
|
||||
class BENCHMARK_CLASS_NAME(groupName, benchmarkName) : public fixtureName \
|
||||
{ \
|
||||
public: \
|
||||
BENCHMARK_CLASS_NAME(groupName, benchmarkName)() : fixtureName() \
|
||||
{ \
|
||||
} \
|
||||
\
|
||||
protected: \
|
||||
virtual void UserBenchmark() override; \
|
||||
\
|
||||
private: \
|
||||
static const std::shared_ptr<::celero::Benchmark> info; \
|
||||
}; \
|
||||
\
|
||||
const std::shared_ptr<::celero::Benchmark> BENCHMARK_CLASS_NAME(groupName, benchmarkName)::info = \
|
||||
::celero::RegisterTest(#groupName, #benchmarkName, samples, iterations, threads, \
|
||||
std::make_shared<::celero::GenericFactory<BENCHMARK_CLASS_NAME(groupName, benchmarkName)>>()); \
|
||||
\
|
||||
void BENCHMARK_CLASS_NAME(groupName, benchmarkName)::UserBenchmark()
|
||||
|
||||
///
|
||||
/// \define BENCHMARK_TEST_IMPL
|
||||
///
|
||||
/// A macro to create a class of a unique name which can be used to register and execute a benchmark test.
|
||||
///
|
||||
#define BENCHMARK_TEST_IMPL(groupName, benchmarkName, fixtureName, samples, iterations, threads, target) \
|
||||
class BENCHMARK_CLASS_NAME(groupName, benchmarkName) : public fixtureName \
|
||||
{ \
|
||||
public: \
|
||||
BENCHMARK_CLASS_NAME(groupName, benchmarkName)() : fixtureName() \
|
||||
{ \
|
||||
} \
|
||||
\
|
||||
protected: \
|
||||
virtual void UserBenchmark() override; \
|
||||
\
|
||||
private: \
|
||||
static const std::shared_ptr<::celero::Benchmark> info; \
|
||||
}; \
|
||||
\
|
||||
const std::shared_ptr<::celero::Benchmark> BENCHMARK_CLASS_NAME(groupName, benchmarkName)::info = \
|
||||
::celero::RegisterTest(#groupName, #benchmarkName, samples, iterations, threads, \
|
||||
std::make_shared<::celero::GenericFactory<BENCHMARK_CLASS_NAME(groupName, benchmarkName)>>(), target); \
|
||||
\
|
||||
void BENCHMARK_CLASS_NAME(groupName, benchmarkName)::UserBenchmark()
|
||||
|
||||
///
|
||||
/// \define BENCHMARK_F
|
||||
///
|
||||
/// \brief A macro to place in user code to define a UserBenchmark function for a benchmark containing a test fixture.
|
||||
///
|
||||
/// Using the BENCHMARK_ macro, this effectivly fills in a class's UserBenchmark() function.
|
||||
///
|
||||
#define BENCHMARK_F(groupName, benchmarkName, fixtureName, samples, iterations) \
|
||||
BENCHMARK_IMPL(groupName, benchmarkName, fixtureName, samples, iterations, 1)
|
||||
|
||||
///
|
||||
/// \define BENCHMARK_T
|
||||
///
|
||||
/// \brief A macro to place in user code to define a UserBenchmark function for a benchmark containing a threaded test fixture.
|
||||
///
|
||||
/// Using the BENCHMARK_ macro, this effectivly fills in a class's UserBenchmark() function.
|
||||
///
|
||||
#define BENCHMARK_T(groupName, benchmarkName, fixtureName, samples, iterations, threads) \
|
||||
BENCHMARK_IMPL(groupName, benchmarkName, fixtureName, samples, iterations, threads)
|
||||
|
||||
///
|
||||
/// \define BENCHMARK_TEST_F
|
||||
///
|
||||
/// \brief A macro to place in user code to define a UserBenchmark function for a benchmark containing a test fixture.
|
||||
///
|
||||
/// Using the BENCHMARK_ macro, this effectivly fills in a class's UserBenchmark() function.
|
||||
///
|
||||
#define BENCHMARK_TEST_F(groupName, benchmarkName, fixtureName, samples, iterations, target) \
|
||||
BENCHMARK_TEST_IMPL(groupName, benchmarkName, fixtureName, samples, iterations, 1, target)
|
||||
|
||||
///
|
||||
/// \define BENCHMARK_TEST_T
|
||||
///
|
||||
/// \brief A macro to place in user code to define a UserBenchmark function for a benchmark containing a threaded test fixture.
|
||||
///
|
||||
/// Using the BENCHMARK_ macro, this effectivly fills in a class's UserBenchmark() function.
|
||||
///
|
||||
#define BENCHMARK_TEST_T(groupName, benchmarkName, fixtureName, samples, iterations, threads, target) \
|
||||
BENCHMARK_TEST_IMPL(groupName, benchmarkName, fixtureName, samples, iterations, threads, target)
|
||||
|
||||
///
|
||||
/// \define BENCHMARK
|
||||
///
|
||||
/// \brief A macro to place in user code to define a UserBenchmark function for a benchmark.
|
||||
///
|
||||
/// Using the BENCHMARK_ macro, this effectivly fills in a class's UserBenchmark() function.
|
||||
///
|
||||
#define BENCHMARK(groupName, benchmarkName, samples, iterations) \
|
||||
BENCHMARK_IMPL(groupName, benchmarkName, ::celero::TestFixture, samples, iterations, 1)
|
||||
|
||||
///
|
||||
/// \define BENCHMARK
|
||||
///
|
||||
/// \brief A macro to place in user code to define a UserBenchmark function for a benchmark.
|
||||
///
|
||||
/// Using the BENCHMARK_ macro, this effectivly fills in a class's UserBenchmark() function.
|
||||
///
|
||||
#define BENCHMARK_TEST(groupName, benchmarkName, samples, iterations, target) \
|
||||
BENCHMARK_TEST_IMPL(groupName, benchmarkName, ::celero::TestFixture, samples, iterations, 1, target)
|
||||
|
||||
///
|
||||
/// \define BASELINE_CLASS_NAME
|
||||
///
|
||||
/// \brief A macro to build a class name based on the test group and baseline names.
|
||||
///
|
||||
#define BASELINE_CLASS_NAME(groupName, baselineName) CeleroUserBaseline##_##groupName##_##baselineName
|
||||
|
||||
///
|
||||
/// \define BASELINE_IMPL
|
||||
///
|
||||
/// A macro to create a class of a unique name which can be used to register and execute a baseline benchmark test.
|
||||
///
|
||||
#define BASELINE_IMPL(groupName, baselineName, fixtureName, samples, iterations, threads, useconds) \
|
||||
class BASELINE_CLASS_NAME(groupName, baselineName) : public fixtureName \
|
||||
{ \
|
||||
public: \
|
||||
BASELINE_CLASS_NAME(groupName, baselineName)() : fixtureName() \
|
||||
{ \
|
||||
} \
|
||||
\
|
||||
protected: \
|
||||
virtual void UserBenchmark() override; \
|
||||
virtual uint64_t HardCodedMeasurement() const override \
|
||||
{ \
|
||||
return uint64_t(useconds); \
|
||||
} \
|
||||
\
|
||||
private: \
|
||||
static const std::shared_ptr<::celero::Benchmark> info; \
|
||||
}; \
|
||||
\
|
||||
const std::shared_ptr<::celero::Benchmark> BASELINE_CLASS_NAME(groupName, baselineName)::info = \
|
||||
::celero::RegisterBaseline(#groupName, #baselineName, samples, iterations, threads, \
|
||||
std::make_shared<::celero::GenericFactory<BASELINE_CLASS_NAME(groupName, baselineName)>>()); \
|
||||
\
|
||||
void BASELINE_CLASS_NAME(groupName, baselineName)::UserBenchmark()
|
||||
|
||||
///
|
||||
/// \define BASELINE_F
|
||||
///
|
||||
/// \brief A macro to place in user code to define a UserBenchmark function for a benchmark containing a test fixture.
|
||||
///
|
||||
/// Using the BASELINE_ macro, this effectivly fills in a class's UserBenchmark() function.
|
||||
///
|
||||
#define BASELINE_F(groupName, baselineName, fixtureName, samples, iterations) \
|
||||
BASELINE_IMPL(groupName, baselineName, fixtureName, samples, iterations, 1, 0)
|
||||
|
||||
///
|
||||
/// \define BASELINE_T
|
||||
///
|
||||
/// \brief A macro to place in user code to define a UserBenchmark function for a benchmark containing a threaded test fixture.
|
||||
///
|
||||
/// Using the BASELINE_ macro, this effectivly fills in a class's UserBenchmark() function.
|
||||
///
|
||||
#define BASELINE_T(groupName, baselineName, fixtureName, samples, iterations, threads) \
|
||||
BASELINE_IMPL(groupName, baselineName, fixtureName, samples, iterations, threads, 0)
|
||||
|
||||
///
|
||||
/// \define BASELINE
|
||||
///
|
||||
/// \brief A macro to place in user code to define a UserBenchmark function for a benchmark.
|
||||
///
|
||||
/// Using the BASELINE_ macro, this effectivly fills in a class's UserBenchmark() function.
|
||||
///
|
||||
#define BASELINE(groupName, baselineName, samples, iterations) \
|
||||
BASELINE_IMPL(groupName, baselineName, ::celero::TestFixture, samples, iterations, 1, 0)
|
||||
|
||||
///
|
||||
/// \define BASELINE_FIXED
|
||||
///
|
||||
/// \brief A macro to place in user code to define a UserBenchmark function for a benchmark with a hard-coded timing.
|
||||
///
|
||||
/// This will NOT perform any timing measurments but will instead use the number of microseconds passed in as the measured time.
|
||||
///
|
||||
/// Using the BASELINE_ macro, this effectivly fills in a class's UserBenchmark() function.
|
||||
///
|
||||
#define BASELINE_FIXED(groupName, baselineName, samples, iterations, useconds) \
|
||||
BASELINE_IMPL(groupName, baselineName, ::celero::TestFixture, samples, iterations, 1, useconds)
|
||||
#define BASELINE_FIXED_F(groupName, baselineName, fixtureName, samples, iterations, useconds) \
|
||||
BASELINE_IMPL(groupName, baselineName, fixtureName, samples, iterations, 1, useconds)
|
||||
#define BASELINE_FIXED_T(groupName, baselineName, fixtureName, samples, iterations, threads, useconds) \
|
||||
BASELINE_IMPL(groupName, baselineName, fixtureName, samples, iterations, threads, useconds)
|
||||
|
||||
#endif
|
935
celero/celero/CommandLine.h
Normal file
935
celero/celero/CommandLine.h
Normal file
@ -0,0 +1,935 @@
|
||||
/*
|
||||
Copyright (c) 2009, Hideyuki Tanaka
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the <organization> nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY <copyright holder> ''AS IS'' AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <typeinfo>
|
||||
#include <vector>
|
||||
|
||||
#ifndef WIN32
|
||||
#include <cxxabi.h>
|
||||
#endif
|
||||
|
||||
namespace cmdline
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
template <typename Target, typename Source, bool Same>
|
||||
class lexical_cast_t
|
||||
{
|
||||
public:
|
||||
static Target cast(const Source &arg)
|
||||
{
|
||||
Target ret;
|
||||
std::stringstream ss;
|
||||
if(!(ss << arg && ss >> ret && ss.eof()))
|
||||
throw std::bad_cast();
|
||||
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Target, typename Source>
|
||||
class lexical_cast_t<Target, Source, true>
|
||||
{
|
||||
public:
|
||||
static Target cast(const Source &arg)
|
||||
{
|
||||
return arg;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Source>
|
||||
class lexical_cast_t<std::string, Source, false>
|
||||
{
|
||||
public:
|
||||
static std::string cast(const Source &arg)
|
||||
{
|
||||
std::ostringstream ss;
|
||||
ss << arg;
|
||||
return ss.str();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Target>
|
||||
class lexical_cast_t<Target, std::string, false>
|
||||
{
|
||||
public:
|
||||
static Target cast(const std::string &arg)
|
||||
{
|
||||
Target ret;
|
||||
std::istringstream ss(arg);
|
||||
if(!(ss >> ret && ss.eof()))
|
||||
throw std::bad_cast();
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T1, typename T2>
|
||||
struct is_same
|
||||
{
|
||||
static const bool value = false;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct is_same<T, T>
|
||||
{
|
||||
static const bool value = true;
|
||||
};
|
||||
|
||||
template <typename Target, typename Source>
|
||||
Target lexical_cast(const Source &arg)
|
||||
{
|
||||
return lexical_cast_t<Target, Source, detail::is_same<Target, Source>::value>::cast(arg);
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
static inline std::string demangle(const std::string &)
|
||||
{
|
||||
return std::string();
|
||||
}
|
||||
#else
|
||||
static inline std::string demangle(const std::string &name)
|
||||
{
|
||||
int status = 0;
|
||||
char *p = abi::__cxa_demangle(name.c_str(), 0, 0, &status);
|
||||
std::string ret(p);
|
||||
free(p);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
template <class T>
|
||||
std::string readable_typename()
|
||||
{
|
||||
return demangle(typeid(T).name());
|
||||
}
|
||||
|
||||
template <class T>
|
||||
std::string default_value(T def)
|
||||
{
|
||||
return detail::lexical_cast<std::string>(def);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline std::string readable_typename<std::string>()
|
||||
{
|
||||
return "string";
|
||||
}
|
||||
|
||||
} // detail
|
||||
|
||||
//-----
|
||||
|
||||
class cmdline_error : public std::exception
|
||||
{
|
||||
public:
|
||||
cmdline_error(const std::string &msg) : msg(msg)
|
||||
{
|
||||
}
|
||||
~cmdline_error() throw()
|
||||
{
|
||||
}
|
||||
const char *what() const throw()
|
||||
{
|
||||
return msg.c_str();
|
||||
}
|
||||
|
||||
private:
|
||||
std::string msg;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct default_reader
|
||||
{
|
||||
T operator()(const std::string &str)
|
||||
{
|
||||
return detail::lexical_cast<T>(str);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct range_reader
|
||||
{
|
||||
range_reader(const T &low, const T &high) : low(low), high(high)
|
||||
{
|
||||
}
|
||||
T operator()(const std::string &s) const
|
||||
{
|
||||
T ret = default_reader<T>()(s);
|
||||
if(!(ret >= low && ret <= high))
|
||||
throw cmdline::cmdline_error("range_error");
|
||||
return ret;
|
||||
}
|
||||
|
||||
private:
|
||||
T low, high;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
range_reader<T> range(const T &low, const T &high)
|
||||
{
|
||||
return range_reader<T>(low, high);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
struct oneof_reader
|
||||
{
|
||||
T operator()(const std::string &s)
|
||||
{
|
||||
T ret = default_reader<T>()(s);
|
||||
if(std::find(alt.begin(), alt.end(), ret) == alt.end())
|
||||
throw cmdline_error("");
|
||||
return ret;
|
||||
}
|
||||
void add(const T &v)
|
||||
{
|
||||
alt.push_back(v);
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<T> alt;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
oneof_reader<T> oneof(T a1)
|
||||
{
|
||||
oneof_reader<T> ret;
|
||||
ret.add(a1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
oneof_reader<T> oneof(T a1, T a2)
|
||||
{
|
||||
oneof_reader<T> ret;
|
||||
ret.add(a1);
|
||||
ret.add(a2);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
oneof_reader<T> oneof(T a1, T a2, T a3)
|
||||
{
|
||||
oneof_reader<T> ret;
|
||||
ret.add(a1);
|
||||
ret.add(a2);
|
||||
ret.add(a3);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
oneof_reader<T> oneof(T a1, T a2, T a3, T a4)
|
||||
{
|
||||
oneof_reader<T> ret;
|
||||
ret.add(a1);
|
||||
ret.add(a2);
|
||||
ret.add(a3);
|
||||
ret.add(a4);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
oneof_reader<T> oneof(T a1, T a2, T a3, T a4, T a5)
|
||||
{
|
||||
oneof_reader<T> ret;
|
||||
ret.add(a1);
|
||||
ret.add(a2);
|
||||
ret.add(a3);
|
||||
ret.add(a4);
|
||||
ret.add(a5);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
oneof_reader<T> oneof(T a1, T a2, T a3, T a4, T a5, T a6)
|
||||
{
|
||||
oneof_reader<T> ret;
|
||||
ret.add(a1);
|
||||
ret.add(a2);
|
||||
ret.add(a3);
|
||||
ret.add(a4);
|
||||
ret.add(a5);
|
||||
ret.add(a6);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
oneof_reader<T> oneof(T a1, T a2, T a3, T a4, T a5, T a6, T a7)
|
||||
{
|
||||
oneof_reader<T> ret;
|
||||
ret.add(a1);
|
||||
ret.add(a2);
|
||||
ret.add(a3);
|
||||
ret.add(a4);
|
||||
ret.add(a5);
|
||||
ret.add(a6);
|
||||
ret.add(a7);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
oneof_reader<T> oneof(T a1, T a2, T a3, T a4, T a5, T a6, T a7, T a8)
|
||||
{
|
||||
oneof_reader<T> ret;
|
||||
ret.add(a1);
|
||||
ret.add(a2);
|
||||
ret.add(a3);
|
||||
ret.add(a4);
|
||||
ret.add(a5);
|
||||
ret.add(a6);
|
||||
ret.add(a7);
|
||||
ret.add(a8);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
oneof_reader<T> oneof(T a1, T a2, T a3, T a4, T a5, T a6, T a7, T a8, T a9)
|
||||
{
|
||||
oneof_reader<T> ret;
|
||||
ret.add(a1);
|
||||
ret.add(a2);
|
||||
ret.add(a3);
|
||||
ret.add(a4);
|
||||
ret.add(a5);
|
||||
ret.add(a6);
|
||||
ret.add(a7);
|
||||
ret.add(a8);
|
||||
ret.add(a9);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
oneof_reader<T> oneof(T a1, T a2, T a3, T a4, T a5, T a6, T a7, T a8, T a9, T a10)
|
||||
{
|
||||
oneof_reader<T> ret;
|
||||
ret.add(a1);
|
||||
ret.add(a2);
|
||||
ret.add(a3);
|
||||
ret.add(a4);
|
||||
ret.add(a5);
|
||||
ret.add(a6);
|
||||
ret.add(a7);
|
||||
ret.add(a8);
|
||||
ret.add(a9);
|
||||
ret.add(a10);
|
||||
return ret;
|
||||
}
|
||||
|
||||
//-----
|
||||
|
||||
class parser
|
||||
{
|
||||
public:
|
||||
parser()
|
||||
{
|
||||
}
|
||||
~parser()
|
||||
{
|
||||
for(std::map<std::string, option_base *>::iterator p = options.begin(); p != options.end(); p++)
|
||||
delete p->second;
|
||||
}
|
||||
|
||||
void add(const std::string &name, char short_name = 0, const std::string &desc = "")
|
||||
{
|
||||
if(options.count(name))
|
||||
throw cmdline_error("multiple definition: " + name);
|
||||
options[name] = new option_without_value(name, short_name, desc);
|
||||
ordered.push_back(options[name]);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void add(const std::string &name, char short_name = 0, const std::string &desc = "", bool need = true, const T def = T())
|
||||
{
|
||||
add(name, short_name, desc, need, def, default_reader<T>());
|
||||
}
|
||||
|
||||
template <class T, class F>
|
||||
void add(const std::string &name, char short_name = 0, const std::string &desc = "", bool need = true, const T def = T(), F reader = F())
|
||||
{
|
||||
if(options.count(name))
|
||||
throw cmdline_error("multiple definition: " + name);
|
||||
options[name] = new option_with_value_with_reader<T, F>(name, short_name, need, def, desc, reader);
|
||||
ordered.push_back(options[name]);
|
||||
}
|
||||
|
||||
void footer(const std::string &f)
|
||||
{
|
||||
ftr = f;
|
||||
}
|
||||
|
||||
void set_program_name(const std::string &name)
|
||||
{
|
||||
prog_name = name;
|
||||
}
|
||||
|
||||
bool exist(const std::string &name) const
|
||||
{
|
||||
if(options.count(name) == 0)
|
||||
throw cmdline_error("there is no flag: --" + name);
|
||||
return options.find(name)->second->has_set();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
const T &get(const std::string &name) const
|
||||
{
|
||||
if(options.count(name) == 0)
|
||||
throw cmdline_error("there is no flag: --" + name);
|
||||
const option_with_value<T> *p = dynamic_cast<const option_with_value<T> *>(options.find(name)->second);
|
||||
if(p == NULL)
|
||||
throw cmdline_error("type mismatch flag '" + name + "'");
|
||||
return p->get();
|
||||
}
|
||||
|
||||
const std::vector<std::string> &rest() const
|
||||
{
|
||||
return others;
|
||||
}
|
||||
|
||||
bool parse(const std::string &arg)
|
||||
{
|
||||
std::vector<std::string> args;
|
||||
|
||||
std::string buf;
|
||||
bool in_quote = false;
|
||||
for(std::string::size_type i = 0; i < arg.length(); i++)
|
||||
{
|
||||
if(arg[i] == '\"')
|
||||
{
|
||||
in_quote = !in_quote;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(arg[i] == ' ' && !in_quote)
|
||||
{
|
||||
args.push_back(buf);
|
||||
buf = "";
|
||||
continue;
|
||||
}
|
||||
|
||||
if(arg[i] == '\\')
|
||||
{
|
||||
i++;
|
||||
if(i >= arg.length())
|
||||
{
|
||||
errors.push_back("unexpected occurrence of '\\' at end of string");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
buf += arg[i];
|
||||
}
|
||||
|
||||
if(in_quote)
|
||||
{
|
||||
errors.push_back("quote is not closed");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(buf.length() > 0)
|
||||
args.push_back(buf);
|
||||
|
||||
for(size_t i = 0; i < args.size(); i++)
|
||||
std::cout << "\"" << args[i] << "\"" << std::endl;
|
||||
|
||||
return parse(args);
|
||||
}
|
||||
|
||||
bool parse(const std::vector<std::string> &args)
|
||||
{
|
||||
int argc = static_cast<int>(args.size());
|
||||
std::vector<const char *> argv(static_cast<size_t>(argc));
|
||||
|
||||
for(int i = 0; i < argc; i++)
|
||||
argv[i] = args[i].c_str();
|
||||
|
||||
return parse(argc, &argv[0]);
|
||||
}
|
||||
|
||||
bool parse(int argc, const char *const argv[])
|
||||
{
|
||||
errors.clear();
|
||||
others.clear();
|
||||
|
||||
if(argc < 1)
|
||||
{
|
||||
errors.push_back("argument number must be longer than 0");
|
||||
return false;
|
||||
}
|
||||
if(prog_name == "")
|
||||
prog_name = argv[0];
|
||||
|
||||
std::map<char, std::string> lookup;
|
||||
for(std::map<std::string, option_base *>::iterator p = options.begin(); p != options.end(); p++)
|
||||
{
|
||||
if(p->first.length() == 0)
|
||||
continue;
|
||||
char initial = p->second->short_name();
|
||||
if(initial)
|
||||
{
|
||||
if(lookup.count(initial) > 0)
|
||||
{
|
||||
lookup[initial] = "";
|
||||
errors.push_back(std::string("short option '") + initial + "' is ambiguous");
|
||||
return false;
|
||||
}
|
||||
else
|
||||
lookup[initial] = p->first;
|
||||
}
|
||||
}
|
||||
|
||||
for(int i = 1; i < argc; i++)
|
||||
{
|
||||
if(strncmp(argv[i], "--", 2) == 0)
|
||||
{
|
||||
const char *p = strchr(argv[i] + 2, '=');
|
||||
if(p)
|
||||
{
|
||||
std::string name(argv[i] + 2, p);
|
||||
std::string val(p + 1);
|
||||
set_option(name, val);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string name(argv[i] + 2);
|
||||
if(options.count(name) == 0)
|
||||
{
|
||||
errors.push_back("undefined option: --" + name);
|
||||
continue;
|
||||
}
|
||||
if(options[name]->has_value())
|
||||
{
|
||||
if(i + 1 >= argc)
|
||||
{
|
||||
errors.push_back("option needs value: --" + name);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
i++;
|
||||
set_option(name, argv[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
set_option(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(strncmp(argv[i], "-", 1) == 0)
|
||||
{
|
||||
if(!argv[i][1])
|
||||
continue;
|
||||
char last = argv[i][1];
|
||||
for(int j = 2; argv[i][j]; j++)
|
||||
{
|
||||
last = argv[i][j];
|
||||
if(lookup.count(argv[i][j - 1]) == 0)
|
||||
{
|
||||
errors.push_back(std::string("undefined short option: -") + argv[i][j - 1]);
|
||||
continue;
|
||||
}
|
||||
if(lookup[argv[i][j - 1]] == "")
|
||||
{
|
||||
errors.push_back(std::string("ambiguous short option: -") + argv[i][j - 1]);
|
||||
continue;
|
||||
}
|
||||
set_option(lookup[argv[i][j - 1]]);
|
||||
}
|
||||
|
||||
if(lookup.count(last) == 0)
|
||||
{
|
||||
errors.push_back(std::string("undefined short option: -") + last);
|
||||
continue;
|
||||
}
|
||||
if(lookup[last] == "")
|
||||
{
|
||||
errors.push_back(std::string("ambiguous short option: -") + last);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(i + 1 < argc && options[lookup[last]]->has_value())
|
||||
{
|
||||
set_option(lookup[last], argv[i + 1]);
|
||||
i++;
|
||||
}
|
||||
else
|
||||
{
|
||||
set_option(lookup[last]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
others.push_back(argv[i]);
|
||||
}
|
||||
}
|
||||
|
||||
for(std::map<std::string, option_base *>::iterator p = options.begin(); p != options.end(); p++)
|
||||
if(!p->second->valid())
|
||||
errors.push_back("need option: --" + std::string(p->first));
|
||||
|
||||
return errors.size() == 0;
|
||||
}
|
||||
|
||||
void parse_check(const std::string &arg)
|
||||
{
|
||||
if(!options.count("help"))
|
||||
add("help", '?', "print this message");
|
||||
check(0, parse(arg));
|
||||
}
|
||||
|
||||
void parse_check(const std::vector<std::string> &args)
|
||||
{
|
||||
if(!options.count("help"))
|
||||
add("help", '?', "print this message");
|
||||
check(static_cast<int>(args.size()), parse(args));
|
||||
}
|
||||
|
||||
void parse_check(int argc, char *argv[])
|
||||
{
|
||||
if(!options.count("help"))
|
||||
add("help", '?', "print this message");
|
||||
check(argc, parse(argc, argv));
|
||||
}
|
||||
|
||||
std::string error() const
|
||||
{
|
||||
return errors.size() > 0 ? errors[0] : "";
|
||||
}
|
||||
|
||||
std::string error_full() const
|
||||
{
|
||||
std::ostringstream oss;
|
||||
for(size_t i = 0; i < errors.size(); i++)
|
||||
oss << errors[i] << std::endl;
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string usage() const
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << "usage: " << prog_name << " ";
|
||||
for(size_t i = 0; i < ordered.size(); i++)
|
||||
{
|
||||
if(ordered[i]->must())
|
||||
oss << ordered[i]->short_description() << " ";
|
||||
}
|
||||
|
||||
oss << "[options] ... " << ftr << std::endl;
|
||||
oss << "options:" << std::endl;
|
||||
|
||||
size_t max_width = 0;
|
||||
for(size_t i = 0; i < ordered.size(); i++)
|
||||
{
|
||||
max_width = std::max(max_width, ordered[i]->name().length());
|
||||
}
|
||||
for(size_t i = 0; i < ordered.size(); i++)
|
||||
{
|
||||
if(ordered[i]->short_name())
|
||||
{
|
||||
oss << " -" << ordered[i]->short_name() << ", ";
|
||||
}
|
||||
else
|
||||
{
|
||||
oss << " ";
|
||||
}
|
||||
|
||||
oss << "--" << ordered[i]->name();
|
||||
for(size_t j = ordered[i]->name().length(); j < max_width + 4; j++)
|
||||
oss << ' ';
|
||||
oss << ordered[i]->description() << std::endl;
|
||||
}
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
private:
|
||||
void check(int argc, bool ok)
|
||||
{
|
||||
if((argc == 1 && !ok) || exist("help"))
|
||||
{
|
||||
std::cerr << usage();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if(!ok)
|
||||
{
|
||||
std::cerr << error() << std::endl << usage();
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void set_option(const std::string &name)
|
||||
{
|
||||
if(options.count(name) == 0)
|
||||
{
|
||||
errors.push_back("undefined option: --" + name);
|
||||
return;
|
||||
}
|
||||
if(!options[name]->set())
|
||||
{
|
||||
errors.push_back("option needs value: --" + name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void set_option(const std::string &name, const std::string &value)
|
||||
{
|
||||
if(options.count(name) == 0)
|
||||
{
|
||||
errors.push_back("undefined option: --" + name);
|
||||
return;
|
||||
}
|
||||
if(!options[name]->set(value))
|
||||
{
|
||||
errors.push_back("option value is invalid: --" + name + "=" + value);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
class option_base
|
||||
{
|
||||
public:
|
||||
virtual ~option_base()
|
||||
{
|
||||
}
|
||||
|
||||
virtual bool has_value() const = 0;
|
||||
virtual bool set() = 0;
|
||||
virtual bool set(const std::string &value) = 0;
|
||||
virtual bool has_set() const = 0;
|
||||
virtual bool valid() const = 0;
|
||||
virtual bool must() const = 0;
|
||||
|
||||
virtual const std::string &name() const = 0;
|
||||
virtual char short_name() const = 0;
|
||||
virtual const std::string &description() const = 0;
|
||||
virtual std::string short_description() const = 0;
|
||||
};
|
||||
|
||||
class option_without_value : public option_base
|
||||
{
|
||||
public:
|
||||
option_without_value(const std::string &name, char short_name, const std::string &desc)
|
||||
: nam(name), snam(short_name), desc(desc), has(false)
|
||||
{
|
||||
}
|
||||
~option_without_value()
|
||||
{
|
||||
}
|
||||
|
||||
bool has_value() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool set()
|
||||
{
|
||||
has = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool set(const std::string &)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool has_set() const
|
||||
{
|
||||
return has;
|
||||
}
|
||||
|
||||
bool valid() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool must() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::string &name() const
|
||||
{
|
||||
return nam;
|
||||
}
|
||||
|
||||
char short_name() const
|
||||
{
|
||||
return snam;
|
||||
}
|
||||
|
||||
const std::string &description() const
|
||||
{
|
||||
return desc;
|
||||
}
|
||||
|
||||
std::string short_description() const
|
||||
{
|
||||
return "--" + nam;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string nam;
|
||||
char snam;
|
||||
std::string desc;
|
||||
bool has;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class option_with_value : public option_base
|
||||
{
|
||||
public:
|
||||
option_with_value(const std::string &name, char short_name, bool need, const T &def, const std::string &desc)
|
||||
: nam(name), snam(short_name), need(need), has(false), def(def), actual(def)
|
||||
{
|
||||
this->desc = full_description(desc);
|
||||
}
|
||||
~option_with_value()
|
||||
{
|
||||
}
|
||||
|
||||
const T &get() const
|
||||
{
|
||||
return actual;
|
||||
}
|
||||
|
||||
bool has_value() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool set()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool set(const std::string &value)
|
||||
{
|
||||
try
|
||||
{
|
||||
actual = read(value);
|
||||
has = true;
|
||||
}
|
||||
catch(const std::exception &)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool has_set() const
|
||||
{
|
||||
return has;
|
||||
}
|
||||
|
||||
bool valid() const
|
||||
{
|
||||
if(need && !has)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool must() const
|
||||
{
|
||||
return need;
|
||||
}
|
||||
|
||||
const std::string &name() const
|
||||
{
|
||||
return nam;
|
||||
}
|
||||
|
||||
char short_name() const
|
||||
{
|
||||
return snam;
|
||||
}
|
||||
|
||||
const std::string &description() const
|
||||
{
|
||||
return desc;
|
||||
}
|
||||
|
||||
std::string short_description() const
|
||||
{
|
||||
return "--" + nam + "=" + detail::readable_typename<T>();
|
||||
}
|
||||
|
||||
protected:
|
||||
std::string full_description(const std::string &description)
|
||||
{
|
||||
return description + " (" + detail::readable_typename<T>() + (need ? "" : " [=" + detail::default_value<T>(def) + "]") + ")";
|
||||
}
|
||||
|
||||
virtual T read(const std::string &s) = 0;
|
||||
|
||||
std::string nam;
|
||||
char snam;
|
||||
bool need;
|
||||
std::string desc;
|
||||
|
||||
bool has;
|
||||
T def;
|
||||
T actual;
|
||||
};
|
||||
|
||||
template <class T, class F>
|
||||
class option_with_value_with_reader : public option_with_value<T>
|
||||
{
|
||||
public:
|
||||
option_with_value_with_reader(const std::string &name, char short_name, bool need, const T def, const std::string &desc, F reader)
|
||||
: option_with_value<T>(name, short_name, need, def, desc), reader(reader)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
T read(const std::string &s)
|
||||
{
|
||||
return reader(s);
|
||||
}
|
||||
|
||||
F reader;
|
||||
};
|
||||
|
||||
std::map<std::string, option_base *> options;
|
||||
std::vector<option_base *> ordered;
|
||||
std::string ftr;
|
||||
|
||||
std::string prog_name;
|
||||
std::vector<std::string> others;
|
||||
|
||||
std::vector<std::string> errors;
|
||||
};
|
||||
|
||||
} // cmdline
|
254
celero/celero/Console.cpp
Normal file
254
celero/celero/Console.cpp
Normal file
@ -0,0 +1,254 @@
|
||||
///
|
||||
/// \author John Farrier
|
||||
///
|
||||
/// \copyright Copyright 2015, 2016, 2017, 2018 John Farrier
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
|
||||
#include <celero/Console.h>
|
||||
|
||||
using namespace celero;
|
||||
|
||||
#ifdef WIN32
|
||||
#include <Windows.h>
|
||||
#include <stdio.h>
|
||||
#else
|
||||
#include <curses.h>
|
||||
#include <iostream>
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
auto WinColor() -> decltype(GetStdHandle(STD_OUTPUT_HANDLE))
|
||||
{
|
||||
auto h = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
CONSOLE_SCREEN_BUFFER_INFO csbiInfo;
|
||||
GetConsoleScreenBufferInfo(h, &csbiInfo);
|
||||
return h;
|
||||
}
|
||||
#endif
|
||||
|
||||
void Red()
|
||||
{
|
||||
#ifdef WIN32
|
||||
auto h = WinColor();
|
||||
SetConsoleTextAttribute(h, FOREGROUND_RED);
|
||||
#else
|
||||
std::cout << "\033[49m\033[31m";
|
||||
#endif
|
||||
}
|
||||
|
||||
void RedBold()
|
||||
{
|
||||
#ifdef WIN32
|
||||
auto h = WinColor();
|
||||
SetConsoleTextAttribute(h, FOREGROUND_RED | FOREGROUND_INTENSITY);
|
||||
#else
|
||||
std::cout << "\033[49m\033[1;31m";
|
||||
#endif
|
||||
}
|
||||
|
||||
void Green()
|
||||
{
|
||||
#ifdef WIN32
|
||||
auto h = WinColor();
|
||||
SetConsoleTextAttribute(h, FOREGROUND_GREEN);
|
||||
#else
|
||||
std::cout << "\033[49m\033[32m";
|
||||
#endif
|
||||
}
|
||||
|
||||
void GreenBold()
|
||||
{
|
||||
#ifdef WIN32
|
||||
auto h = WinColor();
|
||||
SetConsoleTextAttribute(h, FOREGROUND_GREEN | FOREGROUND_INTENSITY);
|
||||
#else
|
||||
std::cout << "\033[49m\033[1;32m";
|
||||
#endif
|
||||
}
|
||||
|
||||
void Blue()
|
||||
{
|
||||
#ifdef WIN32
|
||||
auto h = WinColor();
|
||||
SetConsoleTextAttribute(h, FOREGROUND_BLUE);
|
||||
#else
|
||||
std::cout << "\033[49m\033[34m";
|
||||
#endif
|
||||
}
|
||||
|
||||
void BlueBold()
|
||||
{
|
||||
#ifdef WIN32
|
||||
auto h = WinColor();
|
||||
SetConsoleTextAttribute(h, FOREGROUND_BLUE | FOREGROUND_INTENSITY);
|
||||
#else
|
||||
std::cout << "\033[49m\033[1;34m";
|
||||
#endif
|
||||
}
|
||||
|
||||
void Cyan()
|
||||
{
|
||||
#ifdef WIN32
|
||||
auto h = WinColor();
|
||||
SetConsoleTextAttribute(h, FOREGROUND_BLUE | FOREGROUND_GREEN);
|
||||
#else
|
||||
std::cout << "\033[49m\033[36m";
|
||||
#endif
|
||||
}
|
||||
|
||||
void CyanBold()
|
||||
{
|
||||
#ifdef WIN32
|
||||
auto h = WinColor();
|
||||
SetConsoleTextAttribute(h, FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_INTENSITY);
|
||||
#else
|
||||
std::cout << "\033[49m\033[1;36m";
|
||||
#endif
|
||||
}
|
||||
|
||||
void Yellow()
|
||||
{
|
||||
#ifdef WIN32
|
||||
auto h = WinColor();
|
||||
SetConsoleTextAttribute(h, FOREGROUND_RED | FOREGROUND_GREEN);
|
||||
#else
|
||||
std::cout << "\033[49m\033[33m";
|
||||
#endif
|
||||
}
|
||||
|
||||
void YellowBold()
|
||||
{
|
||||
#ifdef WIN32
|
||||
auto h = WinColor();
|
||||
SetConsoleTextAttribute(h, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY);
|
||||
#else
|
||||
std::cout << "\033[49m\033[1;33m";
|
||||
#endif
|
||||
}
|
||||
|
||||
void White()
|
||||
{
|
||||
#ifdef WIN32
|
||||
auto h = WinColor();
|
||||
SetConsoleTextAttribute(h, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
|
||||
#else
|
||||
std::cout << "\033[49m\033[37m";
|
||||
#endif
|
||||
}
|
||||
|
||||
void WhiteBold()
|
||||
{
|
||||
#ifdef WIN32
|
||||
auto h = WinColor();
|
||||
SetConsoleTextAttribute(h, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
|
||||
#else
|
||||
std::cout << "\033[49m\033[1;37m";
|
||||
#endif
|
||||
}
|
||||
|
||||
void WhiteOnRed()
|
||||
{
|
||||
#ifdef WIN32
|
||||
auto h = WinColor();
|
||||
SetConsoleTextAttribute(h, BACKGROUND_RED | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
|
||||
#else
|
||||
std::cout << "\033[41m\033[37m";
|
||||
#endif
|
||||
}
|
||||
|
||||
void WhiteOnRedBold()
|
||||
{
|
||||
#ifdef WIN32
|
||||
auto h = WinColor();
|
||||
SetConsoleTextAttribute(h, BACKGROUND_RED | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
|
||||
#else
|
||||
std::cout << "\033[41m\033[1;37m";
|
||||
#endif
|
||||
}
|
||||
|
||||
void PurpleBold()
|
||||
{
|
||||
#ifdef WIN32
|
||||
auto h = WinColor();
|
||||
SetConsoleTextAttribute(h, FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
|
||||
#else
|
||||
std::cout << "\033[49m\033[1;38m";
|
||||
#endif
|
||||
}
|
||||
|
||||
void Default()
|
||||
{
|
||||
#ifdef WIN32
|
||||
White();
|
||||
#else
|
||||
std::cout << "\033[0m";
|
||||
#endif
|
||||
}
|
||||
|
||||
void celero::console::SetConsoleColor(const celero::console::ConsoleColor x)
|
||||
{
|
||||
switch(x)
|
||||
{
|
||||
case ConsoleColor_Red:
|
||||
Red();
|
||||
break;
|
||||
case ConsoleColor_Red_Bold:
|
||||
RedBold();
|
||||
break;
|
||||
case ConsoleColor_Green:
|
||||
Green();
|
||||
break;
|
||||
case ConsoleColor_Green_Bold:
|
||||
GreenBold();
|
||||
break;
|
||||
case ConsoleColor_Blue:
|
||||
Blue();
|
||||
break;
|
||||
case ConsoleColor_Blue_Bold:
|
||||
BlueBold();
|
||||
break;
|
||||
case ConsoleColor_Cyan:
|
||||
Cyan();
|
||||
break;
|
||||
case ConsoleColor_Cyan_Bold:
|
||||
CyanBold();
|
||||
break;
|
||||
case ConsoleColor_Yellow:
|
||||
Yellow();
|
||||
break;
|
||||
case ConsoleColor_Yellow_Bold:
|
||||
YellowBold();
|
||||
break;
|
||||
case ConsoleColor_White:
|
||||
White();
|
||||
break;
|
||||
case ConsoleColor_White_Bold:
|
||||
WhiteBold();
|
||||
break;
|
||||
case ConsoleColor_WhiteOnRed:
|
||||
WhiteOnRed();
|
||||
break;
|
||||
case ConsoleColor_WhiteOnRed_Bold:
|
||||
WhiteOnRedBold();
|
||||
break;
|
||||
case ConsoleColor_Purple_Bold:
|
||||
PurpleBold();
|
||||
break;
|
||||
case ConsoleColor_Default:
|
||||
default:
|
||||
Default();
|
||||
break;
|
||||
}
|
||||
}
|
65
celero/celero/Console.h
Normal file
65
celero/celero/Console.h
Normal file
@ -0,0 +1,65 @@
|
||||
#ifndef H_CELERO_CONSOLE_H
|
||||
#define H_CELERO_CONSOLE_H
|
||||
|
||||
///
|
||||
/// \author John Farrier
|
||||
///
|
||||
/// \copyright Copyright 2015, 2016, 2017, 2018 John Farrier
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
|
||||
#include <celero/Export.h>
|
||||
|
||||
namespace celero
|
||||
{
|
||||
///
|
||||
/// \namespace console
|
||||
///
|
||||
/// \author John farrier
|
||||
///
|
||||
namespace console
|
||||
{
|
||||
///
|
||||
/// \enum ConsoleColor
|
||||
///
|
||||
/// \author John farrier
|
||||
///
|
||||
enum ConsoleColor
|
||||
{
|
||||
ConsoleColor_Default,
|
||||
ConsoleColor_Red,
|
||||
ConsoleColor_Red_Bold,
|
||||
ConsoleColor_Green,
|
||||
ConsoleColor_Green_Bold,
|
||||
ConsoleColor_Blue,
|
||||
ConsoleColor_Blue_Bold,
|
||||
ConsoleColor_Cyan,
|
||||
ConsoleColor_Cyan_Bold,
|
||||
ConsoleColor_Yellow,
|
||||
ConsoleColor_Yellow_Bold,
|
||||
ConsoleColor_White,
|
||||
ConsoleColor_White_Bold,
|
||||
ConsoleColor_WhiteOnRed,
|
||||
ConsoleColor_WhiteOnRed_Bold,
|
||||
ConsoleColor_Purple_Bold
|
||||
};
|
||||
|
||||
///
|
||||
/// Set the color of std::out on the console.
|
||||
///
|
||||
CELERO_EXPORT void SetConsoleColor(const celero::console::ConsoleColor x);
|
||||
} // namespace console
|
||||
} // namespace celero
|
||||
|
||||
#endif
|
160
celero/celero/Distribution.cpp
Normal file
160
celero/celero/Distribution.cpp
Normal file
@ -0,0 +1,160 @@
|
||||
///
|
||||
/// \author John Farrier
|
||||
///
|
||||
/// \copyright Copyright 2015, 2016, 2017, 2018 John Farrier
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
|
||||
#include <celero/Distribution.h>
|
||||
#include <celero/Print.h>
|
||||
#include <celero/Utilities.h>
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cmath>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
|
||||
using namespace celero;
|
||||
|
||||
std::vector<uint64_t> celero::BuildDistribution(uint64_t numberOfSamples, uint64_t iterationsPerSample)
|
||||
{
|
||||
std::vector<uint64_t> measurements;
|
||||
|
||||
while(numberOfSamples--)
|
||||
{
|
||||
// Dummy variable
|
||||
auto dummy = uint64_t(0);
|
||||
auto cps = iterationsPerSample;
|
||||
|
||||
// Get the starting time.
|
||||
const auto startTime = celero::timer::GetSystemTime();
|
||||
|
||||
while(cps--)
|
||||
{
|
||||
celero::DoNotOptimizeAway(dummy++);
|
||||
}
|
||||
|
||||
const auto endTime = celero::timer::GetSystemTime();
|
||||
|
||||
measurements.push_back(endTime - startTime);
|
||||
}
|
||||
|
||||
return measurements;
|
||||
}
|
||||
|
||||
void celero::RunDistribution(uint64_t intArgument)
|
||||
{
|
||||
std::vector<double> series1Normalized(intArgument);
|
||||
std::vector<double> series2Normalized(intArgument);
|
||||
std::vector<double> series3Normalized(intArgument);
|
||||
std::vector<double> series4Normalized(intArgument);
|
||||
|
||||
auto series1 = celero::BuildDistribution(intArgument, uint64_t(64));
|
||||
auto series2 = celero::BuildDistribution(intArgument, uint64_t(256));
|
||||
auto series3 = celero::BuildDistribution(intArgument, uint64_t(1024));
|
||||
auto series4 = celero::BuildDistribution(intArgument, uint64_t(4096));
|
||||
|
||||
std::array<std::map<double, uint64_t>, 4> histograms;
|
||||
|
||||
// Find the global max for all tests:
|
||||
auto maxVal = std::max(*(std::max_element(std::begin(series1), std::end(series1))), *(std::max_element(std::begin(series2), std::end(series2))));
|
||||
maxVal = std::max(maxVal, *(std::max_element(std::begin(series3), std::end(series3))));
|
||||
maxVal = std::max(maxVal, *(std::max_element(std::begin(series4), std::end(series4))));
|
||||
|
||||
// Find the global min for all tests:
|
||||
auto minVal = std::min(*(std::min_element(std::begin(series1), std::end(series1))), *(std::min_element(std::begin(series2), std::end(series2))));
|
||||
minVal = std::min(minVal, *(std::min_element(std::begin(series3), std::end(series3))));
|
||||
minVal = std::min(minVal, *(std::min_element(std::begin(series4), std::end(series4))));
|
||||
|
||||
// Normalize all vectors:
|
||||
auto normalize = [minVal, maxVal](uint64_t val) -> double {
|
||||
if(val >= minVal)
|
||||
{
|
||||
if(val <= maxVal)
|
||||
{
|
||||
const auto delta = maxVal - minVal;
|
||||
val -= minVal;
|
||||
return static_cast<double>(val) / static_cast<double>(delta);
|
||||
}
|
||||
|
||||
return static_cast<double>(maxVal);
|
||||
}
|
||||
|
||||
return static_cast<double>(minVal);
|
||||
};
|
||||
|
||||
std::transform(std::begin(series1), std::end(series1), std::begin(series1Normalized),
|
||||
[normalize](const uint64_t val) -> double { return normalize(val); });
|
||||
|
||||
std::transform(std::begin(series2), std::end(series2), std::begin(series2Normalized),
|
||||
[normalize](const uint64_t val) -> double { return normalize(val); });
|
||||
|
||||
std::transform(std::begin(series3), std::end(series3), std::begin(series3Normalized),
|
||||
[normalize](const uint64_t val) -> double { return normalize(val); });
|
||||
|
||||
std::transform(std::begin(series4), std::end(series4), std::begin(series4Normalized),
|
||||
[normalize](const uint64_t val) -> double { return normalize(val); });
|
||||
|
||||
// Build histograms of each of the series:
|
||||
std::for_each(std::begin(series1Normalized), std::end(series1Normalized),
|
||||
[&histograms](const double val) { histograms[0][static_cast<int>(val * 1024)]++; });
|
||||
|
||||
std::for_each(std::begin(series2Normalized), std::end(series2Normalized),
|
||||
[&histograms](const double val) { histograms[1][static_cast<int>(val * 1024)]++; });
|
||||
|
||||
std::for_each(std::begin(series3Normalized), std::end(series3Normalized),
|
||||
[&histograms](const double val) { histograms[2][static_cast<int>(val * 1024)]++; });
|
||||
|
||||
std::for_each(std::begin(series4Normalized), std::end(series4Normalized),
|
||||
[&histograms](const double val) { histograms[3][static_cast<int>(val * 1024)]++; });
|
||||
|
||||
// Find the maximum length of all histograms:
|
||||
auto maxLen = size_t(0);
|
||||
maxLen = std::max(maxLen, histograms[0].size());
|
||||
maxLen = std::max(maxLen, histograms[1].size());
|
||||
maxLen = std::max(maxLen, histograms[2].size());
|
||||
maxLen = std::max(maxLen, histograms[3].size());
|
||||
|
||||
// Write out a CSV file that contains all four series:
|
||||
std::ofstream os;
|
||||
os.open("celeroDistribution.csv");
|
||||
|
||||
os << "64,,256,,1024,,4096,," << std::endl;
|
||||
|
||||
for(size_t i = 0; i < maxLen; ++i)
|
||||
{
|
||||
for(size_t j = 0; j < histograms.size(); j++)
|
||||
{
|
||||
if(i < histograms[j].size())
|
||||
{
|
||||
auto element = std::begin(histograms[j]);
|
||||
for(size_t k = 0; k < i; k++)
|
||||
{
|
||||
++element;
|
||||
}
|
||||
|
||||
os << element->first << "," << element->second << ",";
|
||||
}
|
||||
else
|
||||
{
|
||||
os << ",,";
|
||||
}
|
||||
}
|
||||
|
||||
os << std::endl;
|
||||
}
|
||||
|
||||
os.close();
|
||||
}
|
39
celero/celero/Distribution.h
Normal file
39
celero/celero/Distribution.h
Normal file
@ -0,0 +1,39 @@
|
||||
#ifndef H_CELERO_DISTRIBUTION_H
|
||||
#define H_CELERO_DISTRIBUTION_H
|
||||
|
||||
///
|
||||
/// \author John Farrier
|
||||
///
|
||||
/// \copyright Copyright 2015, 2016, 2017, 2018 John Farrier
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
|
||||
#include <celero/Export.h>
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
namespace celero
|
||||
{
|
||||
///
|
||||
/// Collects results from Celero for analysis of a hard-coded internal trivial measurement case.
|
||||
///
|
||||
CELERO_EXPORT std::vector<uint64_t> BuildDistribution(uint64_t numberOfSamples, uint64_t iterationsPerSample);
|
||||
|
||||
///
|
||||
/// Builds a .csv file to help determine Celero's measurement distribution.
|
||||
///
|
||||
CELERO_EXPORT void RunDistribution(uint64_t iterationsPerSample);
|
||||
}
|
||||
|
||||
#endif
|
251
celero/celero/Exceptions.cpp
Normal file
251
celero/celero/Exceptions.cpp
Normal file
@ -0,0 +1,251 @@
|
||||
///
|
||||
/// \author Peter Azmanov
|
||||
///
|
||||
/// \copyright Copyright 2016, 2017, 2018 John Farrier
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
|
||||
#include <celero/Exceptions.h>
|
||||
|
||||
#include <celero/Console.h>
|
||||
#include <celero/TestFixture.h>
|
||||
|
||||
#ifdef WIN32
|
||||
#include <Windows.h>
|
||||
#endif // WIN32
|
||||
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
|
||||
//
|
||||
// Macros and general logics below taken from Google Test code,
|
||||
// see gtest/internal/gtest-port.h
|
||||
// gtest/src/gtest.cc
|
||||
//
|
||||
|
||||
#ifndef CELERO_HAS_EXCEPTIONS
|
||||
// The user didn't tell us whether exceptions are enabled, so we need
|
||||
// to figure it out.
|
||||
#if defined(_MSC_VER) || defined(__BORLANDC__)
|
||||
// MSVC's and C++Builder's implementations of the STL use the _HAS_EXCEPTIONS
|
||||
// macro to enable exceptions, so we'll do the same.
|
||||
// Assumes that exceptions are enabled by default.
|
||||
#ifndef _HAS_EXCEPTIONS
|
||||
#define _HAS_EXCEPTIONS 1
|
||||
#endif // _HAS_EXCEPTIONS
|
||||
#define CELERO_HAS_EXCEPTIONS _HAS_EXCEPTIONS
|
||||
#elif defined(__GNUC__) && __EXCEPTIONS
|
||||
// gcc defines __EXCEPTIONS to 1 iff exceptions are enabled.
|
||||
#define CELERO_HAS_EXCEPTIONS 1
|
||||
#elif defined(__SUNPRO_CC)
|
||||
// Sun Pro CC supports exceptions. However, there is no compile-time way of
|
||||
// detecting whether they are enabled or not. Therefore, we assume that
|
||||
// they are enabled unless the user tells us otherwise.
|
||||
#define CELERO_HAS_EXCEPTIONS 1
|
||||
#elif defined(__IBMCPP__) && __EXCEPTIONS
|
||||
// xlC defines __EXCEPTIONS to 1 iff exceptions are enabled.
|
||||
#define CELERO_HAS_EXCEPTIONS 1
|
||||
#elif defined(__HP_aCC)
|
||||
// Exception handling is in effect by default in HP aCC compiler. It has to
|
||||
// be turned of by +noeh compiler option if desired.
|
||||
#define CELERO_HAS_EXCEPTIONS 1
|
||||
#else
|
||||
// For other compilers, we assume exceptions are disabled to be
|
||||
// conservative.
|
||||
#define CELERO_HAS_EXCEPTIONS 0
|
||||
#endif // defined(_MSC_VER) || defined(__BORLANDC__)
|
||||
#endif // CELERO_HAS_EXCEPTIONS
|
||||
|
||||
// Determine whether the compiler supports Microsoft's Structured Exception
|
||||
// Handling. This is supported by several Windows compilers but generally
|
||||
// does not exist on any other system.
|
||||
#ifndef CELERO_HAS_SEH
|
||||
// The user didn't tell us, so we need to figure it out.
|
||||
|
||||
#if defined(_MSC_VER) || defined(__BORLANDC__)
|
||||
// These two compilers are known to support SEH.
|
||||
#define CELERO_HAS_SEH 1
|
||||
#else
|
||||
// Assume no SEH.
|
||||
#define CELERO_HAS_SEH 0
|
||||
#endif
|
||||
|
||||
#endif // CELERO_HAS_SEH
|
||||
|
||||
namespace celero
|
||||
{
|
||||
bool ExceptionSettings::GetCatchExceptions()
|
||||
{
|
||||
return ExceptionSettings::instance().catchExceptions;
|
||||
}
|
||||
|
||||
void ExceptionSettings::SetCatchExceptions(bool x)
|
||||
{
|
||||
ExceptionSettings::instance().catchExceptions = x;
|
||||
}
|
||||
|
||||
ExceptionSettings& ExceptionSettings::instance()
|
||||
{
|
||||
static ExceptionSettings settings;
|
||||
return settings;
|
||||
}
|
||||
|
||||
#if CELERO_HAS_SEH
|
||||
int HandleSEH(DWORD exceptionCode)
|
||||
{
|
||||
// see https://support.microsoft.com/en-us/kb/185294
|
||||
const DWORD cppExceptionCode = 0xe06d7363;
|
||||
|
||||
if((exceptionCode == EXCEPTION_BREAKPOINT) || (exceptionCode == cppExceptionCode))
|
||||
{
|
||||
return EXCEPTION_EXECUTE_HANDLER;
|
||||
}
|
||||
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
const char* const ExceptionCodeToStr(DWORD exceptionCode)
|
||||
{
|
||||
switch(exceptionCode)
|
||||
{
|
||||
case EXCEPTION_ACCESS_VIOLATION:
|
||||
return "EXCEPTION_ACCESS_VIOLATION";
|
||||
|
||||
case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
|
||||
return "EXCEPTION_ARRAY_BOUNDS_EXCEEDED";
|
||||
|
||||
case EXCEPTION_BREAKPOINT:
|
||||
return "EXCEPTION_BREAKPOINT";
|
||||
|
||||
case EXCEPTION_DATATYPE_MISALIGNMENT:
|
||||
return "EXCEPTION_DATATYPE_MISALIGNMENT";
|
||||
|
||||
case EXCEPTION_FLT_DENORMAL_OPERAND:
|
||||
return "EXCEPTION_FLT_DENORMAL_OPERAND";
|
||||
|
||||
case EXCEPTION_FLT_DIVIDE_BY_ZERO:
|
||||
return "EXCEPTION_FLT_DIVIDE_BY_ZERO";
|
||||
|
||||
case EXCEPTION_FLT_INEXACT_RESULT:
|
||||
return "EXCEPTION_FLT_INEXACT_RESULT";
|
||||
|
||||
case EXCEPTION_FLT_INVALID_OPERATION:
|
||||
return "EXCEPTION_FLT_INVALID_OPERATION";
|
||||
|
||||
case EXCEPTION_FLT_OVERFLOW:
|
||||
return "EXCEPTION_FLT_OVERFLOW";
|
||||
|
||||
case EXCEPTION_FLT_STACK_CHECK:
|
||||
return "EXCEPTION_FLT_STACK_CHECK";
|
||||
|
||||
case EXCEPTION_FLT_UNDERFLOW:
|
||||
return "EXCEPTION_FLT_UNDERFLOW";
|
||||
|
||||
case EXCEPTION_GUARD_PAGE:
|
||||
return "EXCEPTION_GUARD_PAGE";
|
||||
|
||||
case EXCEPTION_ILLEGAL_INSTRUCTION:
|
||||
return "EXCEPTION_ILLEGAL_INSTRUCTION";
|
||||
|
||||
case EXCEPTION_IN_PAGE_ERROR:
|
||||
return "EXCEPTION_IN_PAGE_ERROR";
|
||||
|
||||
case EXCEPTION_INT_DIVIDE_BY_ZERO:
|
||||
return "EXCEPTION_INT_DIVIDE_BY_ZERO";
|
||||
|
||||
case EXCEPTION_INT_OVERFLOW:
|
||||
return "EXCEPTION_INT_OVERFLOW";
|
||||
|
||||
case EXCEPTION_INVALID_DISPOSITION:
|
||||
return "EXCEPTION_INVALID_DISPOSITION";
|
||||
|
||||
case EXCEPTION_INVALID_HANDLE:
|
||||
return "EXCEPTION_INVALID_HANDLE";
|
||||
|
||||
case EXCEPTION_NONCONTINUABLE_EXCEPTION:
|
||||
return "EXCEPTION_NONCONTINUABLE_EXCEPTION";
|
||||
|
||||
case EXCEPTION_PRIV_INSTRUCTION:
|
||||
return "EXCEPTION_PRIV_INSTRUCTION";
|
||||
|
||||
case EXCEPTION_SINGLE_STEP:
|
||||
return "EXCEPTION_SINGLE_STEP";
|
||||
|
||||
case EXCEPTION_STACK_OVERFLOW:
|
||||
return "EXCEPTION_STACK_OVERFLOW";
|
||||
|
||||
case STATUS_UNWIND_CONSOLIDATE:
|
||||
return "STATUS_UNWIND_CONSOLIDATE";
|
||||
|
||||
default:
|
||||
return "Unknown exception code.";
|
||||
}
|
||||
}
|
||||
#endif // CELERO_HAS_SEH
|
||||
|
||||
std::pair<bool, uint64_t> RunAndCatchSEHExc(TestFixture& test, uint64_t threads, uint64_t calls,
|
||||
const celero::TestFixture::ExperimentValue& experimentValue)
|
||||
{
|
||||
#if CELERO_HAS_SEH
|
||||
__try
|
||||
{
|
||||
return std::make_pair(true, test.run(threads, calls, experimentValue));
|
||||
}
|
||||
__except(HandleSEH(GetExceptionCode()))
|
||||
{
|
||||
const auto exceptionCode = GetExceptionCode();
|
||||
celero::console::SetConsoleColor(celero::console::ConsoleColor_Red);
|
||||
std::cout << "SEH exception " << ExceptionCodeToStr(exceptionCode) << std::endl;
|
||||
celero::console::SetConsoleColor(celero::console::ConsoleColor_Default);
|
||||
return std::make_pair(false, 0);
|
||||
}
|
||||
#else // CELERO_HAS_SEH
|
||||
return std::make_pair(true, test.run(threads, calls, experimentValue));
|
||||
#endif // CELERO_HAS_SEH
|
||||
}
|
||||
|
||||
std::pair<bool, uint64_t> RunAndCatchExc(TestFixture& test, uint64_t threads, uint64_t calls,
|
||||
const celero::TestFixture::ExperimentValue& experimentValue)
|
||||
{
|
||||
if(ExceptionSettings::GetCatchExceptions() == true)
|
||||
{
|
||||
#if CELERO_HAS_EXCEPTIONS
|
||||
try
|
||||
{
|
||||
return RunAndCatchSEHExc(test, threads, calls, experimentValue);
|
||||
}
|
||||
catch(const std::exception& e)
|
||||
{
|
||||
celero::console::SetConsoleColor(celero::console::ConsoleColor_Red);
|
||||
std::cout << "C++ exception \"" << e.what() << "\"" << std::endl;
|
||||
celero::console::SetConsoleColor(celero::console::ConsoleColor_Default);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
celero::console::SetConsoleColor(celero::console::ConsoleColor_Red);
|
||||
std::cout << "Unknown C++ exception" << std::endl;
|
||||
celero::console::SetConsoleColor(celero::console::ConsoleColor_Default);
|
||||
}
|
||||
|
||||
return std::make_pair(false, 0);
|
||||
#else // CELERO_HAS_EXCEPTIONS
|
||||
return RunAndCatchSEHExc(test, threads, calls, experimentValue);
|
||||
#endif // CELERO_HAS_EXCEPTIONS
|
||||
}
|
||||
else
|
||||
{
|
||||
return std::make_pair(true, test.run(threads, calls, experimentValue));
|
||||
}
|
||||
}
|
||||
} // namespace celero
|
64
celero/celero/Exceptions.h
Normal file
64
celero/celero/Exceptions.h
Normal file
@ -0,0 +1,64 @@
|
||||
#ifndef H_CELERO_EXCEPTIONS_H
|
||||
#define H_CELERO_EXCEPTIONS_H
|
||||
|
||||
///
|
||||
/// \author Peter Azmanov
|
||||
///
|
||||
/// \copyright Copyright 2015, 2016, 2017, 2018 John Farrier
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
|
||||
#include <celero/TestFixture.h>
|
||||
#include <cstdint>
|
||||
#include <utility>
|
||||
|
||||
namespace celero
|
||||
{
|
||||
///
|
||||
/// A Singleton storing exception settings (currently only one flag)
|
||||
///
|
||||
class ExceptionSettings
|
||||
{
|
||||
public:
|
||||
///
|
||||
/// Get a flag indicating whether Celero should catch exceptions or not
|
||||
///
|
||||
static bool GetCatchExceptions();
|
||||
|
||||
///
|
||||
/// Set a flag indicating whether Celero should catch exceptions or not
|
||||
///
|
||||
static void SetCatchExceptions(bool catchExceptions);
|
||||
|
||||
private:
|
||||
static ExceptionSettings& instance();
|
||||
|
||||
private:
|
||||
bool catchExceptions{true};
|
||||
};
|
||||
|
||||
///
|
||||
/// Run test and catch SEH exceptions if they are supported by compiler
|
||||
///
|
||||
std::pair<bool, uint64_t> RunAndCatchSEHExc(TestFixture& test, uint64_t threads, uint64_t calls,
|
||||
const celero::TestFixture::ExperimentValue& experimentValue);
|
||||
|
||||
///
|
||||
/// Run test and catch all exceptions we can
|
||||
///
|
||||
std::pair<bool, uint64_t> RunAndCatchExc(TestFixture& test, uint64_t threads, uint64_t calls,
|
||||
const celero::TestFixture::ExperimentValue& experimentValue);
|
||||
} // namespace celero
|
||||
|
||||
#endif
|
360
celero/celero/Executor.cpp
Normal file
360
celero/celero/Executor.cpp
Normal file
@ -0,0 +1,360 @@
|
||||
///
|
||||
/// \author John Farrier
|
||||
///
|
||||
/// \copyright Copyright 2015, 2016, 2017, 2018 John Farrier
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
|
||||
#include <celero/Benchmark.h>
|
||||
#include <celero/Callbacks.h>
|
||||
#include <celero/Celero.h>
|
||||
#include <celero/Console.h>
|
||||
#include <celero/Exceptions.h>
|
||||
#include <celero/Executor.h>
|
||||
#include <celero/Print.h>
|
||||
#include <celero/TestVector.h>
|
||||
#include <celero/UserDefinedMeasurementCollector.h>
|
||||
#include <celero/Utilities.h>
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
|
||||
using namespace celero;
|
||||
|
||||
///
|
||||
/// A local function to figure out how many iterations and samples are required when the user doesn't specify any.
|
||||
///
|
||||
bool AdjustSampleAndIterationSize(std::shared_ptr<celero::ExperimentResult> r)
|
||||
{
|
||||
if(r->getExperiment()->getSamples() == 0)
|
||||
{
|
||||
// The smallest test should take at least 10x as long as our timer's resolution.
|
||||
// I chose "10x" arbitrarily.
|
||||
const auto minTestTime = static_cast<int64_t>(celero::timer::CachePerformanceFrequency(true) * 1e6) * 10;
|
||||
|
||||
// Compute a good number to use for iterations and set the sample size to 30.
|
||||
auto test = r->getExperiment()->getFactory()->Create();
|
||||
auto testTime = int64_t(0);
|
||||
auto testIterations = int64_t(1);
|
||||
|
||||
while(testTime < minTestTime)
|
||||
{
|
||||
const auto runResult = RunAndCatchExc(*test, r->getExperiment()->getThreads(), testIterations, r->getProblemSpaceValue());
|
||||
|
||||
if(runResult.first == false)
|
||||
{
|
||||
return false; // something bad happened
|
||||
}
|
||||
|
||||
testTime = runResult.second;
|
||||
|
||||
if(testTime < minTestTime)
|
||||
{
|
||||
testIterations *= 2;
|
||||
}
|
||||
}
|
||||
|
||||
const auto iterations = static_cast<uint64_t>(std::max(static_cast<double>(testIterations), 1000000.0 / testTime));
|
||||
auto experiment = r->getExperiment();
|
||||
|
||||
experiment->setIterations(iterations);
|
||||
experiment->setSamples(30);
|
||||
|
||||
r->setProblemSpaceValue(r->getProblemSpaceValue(), r->getProblemSpaceValueScale(), iterations);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
///
|
||||
/// A local function to support running an individual user-defined function for measurement.
|
||||
///
|
||||
bool ExecuteProblemSpace(std::shared_ptr<celero::ExperimentResult> r)
|
||||
{
|
||||
// Define a small internal function object to use to uniformly execute the tests.
|
||||
auto testRunner = [r](const bool record, std::shared_ptr<UserDefinedMeasurementCollector> udmCollector) {
|
||||
auto test = r->getExperiment()->getFactory()->Create();
|
||||
|
||||
const auto runResult = RunAndCatchExc(*test, r->getExperiment()->getThreads(), r->getProblemSpaceIterations(), r->getProblemSpaceValue());
|
||||
|
||||
if(runResult.first == false)
|
||||
{
|
||||
// something bad happened
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto testTime = runResult.second;
|
||||
|
||||
// Save test results
|
||||
if(record == true)
|
||||
{
|
||||
r->getTimeStatistics()->addSample(testTime);
|
||||
r->getExperiment()->incrementTotalRunTime(testTime);
|
||||
|
||||
if(udmCollector != nullptr)
|
||||
{
|
||||
udmCollector->collect(test);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
if(r->getExperiment()->getSamples() > 0)
|
||||
{
|
||||
// make a first pass to maybe cache instructions/data or other kinds of fist-run-only costs
|
||||
if(testRunner(false, nullptr) == false)
|
||||
{
|
||||
r->setFailure(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
auto udmCollector = std::make_shared<UserDefinedMeasurementCollector>(r->getExperiment()->getFactory()->Create());
|
||||
|
||||
for(auto i = r->getExperiment()->getSamples(); i > 0; --i)
|
||||
{
|
||||
if(testRunner(true, udmCollector) == false)
|
||||
{
|
||||
r->setFailure(true);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
r->setUserDefinedMeasurements(udmCollector);
|
||||
r->setComplete(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "Celero: Test \"" << r->getExperiment()->getBenchmark()->getName() << "::" << r->getExperiment()->getName()
|
||||
<< "\" must have at least 1 sample." << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void executor::RunAll()
|
||||
{
|
||||
executor::RunAllBaselines();
|
||||
executor::RunAllExperiments();
|
||||
}
|
||||
|
||||
void executor::RunAllBaselines()
|
||||
{
|
||||
// Run through all the tests in ascending order.
|
||||
for(size_t i = 0; i < celero::TestVector::Instance().size(); i++)
|
||||
{
|
||||
auto bmark = celero::TestVector::Instance()[i];
|
||||
executor::RunBaseline(bmark);
|
||||
}
|
||||
}
|
||||
|
||||
void executor::RunAllExperiments()
|
||||
{
|
||||
// Run through all the tests in ascending order.
|
||||
for(size_t i = 0; i < celero::TestVector::Instance().size(); i++)
|
||||
{
|
||||
auto bmark = celero::TestVector::Instance()[i];
|
||||
executor::RunExperiments(bmark);
|
||||
}
|
||||
}
|
||||
|
||||
void executor::RunBaseline(std::shared_ptr<Benchmark> bmark)
|
||||
{
|
||||
auto baselineExperiment = bmark->getBaseline();
|
||||
|
||||
if(baselineExperiment != nullptr)
|
||||
{
|
||||
// Populate the problem space with a test fixture instantiation.
|
||||
{
|
||||
const auto testValues = baselineExperiment->getFactory()->Create()->getExperimentValues();
|
||||
const auto valueResultScale = baselineExperiment->getFactory()->Create()->getExperimentValueResultScale();
|
||||
|
||||
for(auto i : testValues)
|
||||
{
|
||||
if(i.Iterations > 0)
|
||||
{
|
||||
baselineExperiment->addProblemSpace(i.Value, static_cast<double>(valueResultScale), i.Iterations);
|
||||
}
|
||||
else
|
||||
{
|
||||
baselineExperiment->addProblemSpace(i.Value, static_cast<double>(valueResultScale), baselineExperiment->getIterations());
|
||||
}
|
||||
}
|
||||
|
||||
// Add a single default problem space if none was specified.
|
||||
// This is needed to get the result size later.
|
||||
if(baselineExperiment->getResultSize() == 0)
|
||||
{
|
||||
baselineExperiment->addProblemSpace(static_cast<int64_t>(TestFixture::Constants::NoProblemSpaceValue));
|
||||
}
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < baselineExperiment->getResultSize(); i++)
|
||||
{
|
||||
auto r = baselineExperiment->getResult(i);
|
||||
assert(r != nullptr);
|
||||
|
||||
Printer::get().TableRowExperimentHeader(r->getExperiment());
|
||||
|
||||
// Do a quick sample, if necessary, and adjust sample and iteration sizes, if necessary.
|
||||
if(AdjustSampleAndIterationSize(r) == true)
|
||||
{
|
||||
// Describe the beginning of the run.
|
||||
Printer::get().TableRowProblemSpaceHeader(r);
|
||||
|
||||
if(ExecuteProblemSpace(r))
|
||||
{
|
||||
// Describe the end of the run.
|
||||
Printer::get().TableResult(r);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
r->setFailure(true);
|
||||
}
|
||||
|
||||
celero::impl::ExperimentResultComplete(r);
|
||||
}
|
||||
|
||||
celero::impl::ExperimentComplete(baselineExperiment);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "No Baseline case defined for \"" + bmark->getName() + "\". Exiting.";
|
||||
std::exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
void executor::RunExperiments(std::shared_ptr<Benchmark> bmark)
|
||||
{
|
||||
const auto experimentSize = bmark->getExperimentSize();
|
||||
|
||||
for(size_t i = 0; i < experimentSize; i++)
|
||||
{
|
||||
auto e = bmark->getExperiment(i);
|
||||
assert(e != nullptr);
|
||||
|
||||
executor::Run(e);
|
||||
}
|
||||
}
|
||||
|
||||
void executor::Run(std::shared_ptr<Experiment> e)
|
||||
{
|
||||
auto bmark = e->getBenchmark();
|
||||
auto baseline = bmark->getBaseline();
|
||||
|
||||
if(baseline->getResultSize() == 0 || baseline->getResult(0)->getComplete() == false)
|
||||
{
|
||||
if(baseline->getResultSize() != 0 && baseline->getResult(0)->getFailure())
|
||||
{
|
||||
Printer::get().TableRowExperimentHeader(e.get());
|
||||
Printer::get().TableRowFailure("Baseline failure, skip");
|
||||
|
||||
// Add result output failed result
|
||||
e->addProblemSpace(0);
|
||||
|
||||
auto r = e->getResult(0);
|
||||
r->setFailure(true);
|
||||
celero::impl::ExperimentResultComplete(r);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
executor::RunBaseline(bmark);
|
||||
}
|
||||
|
||||
// Populate the problem space with a fake test fixture instantiation.
|
||||
{
|
||||
const auto testValues = e->getFactory()->Create()->getExperimentValues();
|
||||
const auto valueResultScale = e->getFactory()->Create()->getExperimentValueResultScale();
|
||||
|
||||
for(auto i : testValues)
|
||||
{
|
||||
if(i.Iterations > 0)
|
||||
{
|
||||
e->addProblemSpace(i.Value, valueResultScale, i.Iterations);
|
||||
}
|
||||
else
|
||||
{
|
||||
e->addProblemSpace(i.Value, valueResultScale, e->getIterations());
|
||||
}
|
||||
}
|
||||
|
||||
// Add a single default problem space if none was specified.
|
||||
// This is needed to get the result size later.
|
||||
if(e->getResultSize() == 0)
|
||||
{
|
||||
e->addProblemSpace(0);
|
||||
}
|
||||
}
|
||||
|
||||
// Result size will grow based on the problem spaces added above.
|
||||
for(size_t i = 0; i < e->getResultSize(); i++)
|
||||
{
|
||||
auto r = e->getResult(i);
|
||||
|
||||
Printer::get().TableRowExperimentHeader(r->getExperiment());
|
||||
|
||||
// Do a quick sample, if necessary, and adjust sample and iteration sizes, if necessary.
|
||||
const auto adjustSuccess = AdjustSampleAndIterationSize(r);
|
||||
|
||||
if(adjustSuccess == true)
|
||||
{
|
||||
// Describe the beginning of the run.
|
||||
Printer::get().TableRowProblemSpaceHeader(r);
|
||||
|
||||
if(ExecuteProblemSpace(r))
|
||||
{
|
||||
// Describe the end of the run.
|
||||
Printer::get().TableResult(r);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
r->setFailure(true);
|
||||
}
|
||||
|
||||
celero::impl::ExperimentResultComplete(r);
|
||||
}
|
||||
|
||||
celero::impl::ExperimentComplete(e);
|
||||
}
|
||||
|
||||
void executor::Run(std::shared_ptr<Benchmark> bmark)
|
||||
{
|
||||
executor::RunBaseline(bmark);
|
||||
executor::RunExperiments(bmark);
|
||||
}
|
||||
|
||||
void executor::Run(const std::string& benchmarkName)
|
||||
{
|
||||
auto bmark = celero::TestVector::Instance()[benchmarkName];
|
||||
|
||||
if(bmark != nullptr)
|
||||
{
|
||||
executor::Run(bmark);
|
||||
}
|
||||
}
|
||||
|
||||
void executor::Run(const std::string& benchmarkName, const std::string& experimentName)
|
||||
{
|
||||
auto bmark = celero::TestVector::Instance()[benchmarkName];
|
||||
|
||||
if(bmark != nullptr)
|
||||
{
|
||||
auto e = bmark->getExperiment(experimentName);
|
||||
assert(e != nullptr);
|
||||
executor::Run(e);
|
||||
}
|
||||
}
|
82
celero/celero/Executor.h
Normal file
82
celero/celero/Executor.h
Normal file
@ -0,0 +1,82 @@
|
||||
#ifndef H_CELERO_EXECUTOR_H
|
||||
#define H_CELERO_EXECUTOR_H
|
||||
|
||||
///
|
||||
/// \author John Farrier
|
||||
///
|
||||
/// \copyright Copyright 2015, 2016, 2017, 2018 John Farrier
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
|
||||
#include <celero/Benchmark.h>
|
||||
#include <celero/Export.h>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace celero
|
||||
{
|
||||
namespace executor
|
||||
{
|
||||
///
|
||||
/// Run all baselines and experiments registered within the final application.
|
||||
///
|
||||
void RunAll();
|
||||
|
||||
///
|
||||
/// Run all baselines (but not experiments) registered within the final application.
|
||||
///
|
||||
void RunAllBaselines();
|
||||
|
||||
///
|
||||
/// Run a specific benchmark's baseline.
|
||||
///
|
||||
void RunBaseline(std::shared_ptr<Benchmark> x);
|
||||
|
||||
///
|
||||
/// Run all experiments registered within the final application.
|
||||
///
|
||||
void RunAllExperiments();
|
||||
|
||||
///
|
||||
/// Run all experiments within a specific benchmark.
|
||||
///
|
||||
void RunExperiments(std::shared_ptr<Benchmark> x);
|
||||
|
||||
///
|
||||
/// Run a specific benchmark.
|
||||
///
|
||||
void Run(std::shared_ptr<Benchmark> x);
|
||||
|
||||
///
|
||||
/// Run a specific experiment.
|
||||
///
|
||||
/// If the baseline is not complete for the given experiment, it will be executed first.
|
||||
///
|
||||
void Run(std::shared_ptr<Experiment> x);
|
||||
|
||||
///
|
||||
/// Run a specific benchmark with the specified name.
|
||||
///
|
||||
void Run(const std::string& group);
|
||||
|
||||
///
|
||||
/// Run a specific benchmark with the specified name and one specific experiment within it.
|
||||
///
|
||||
/// If the baseline is not complete for the given experiment, it will be executed first.
|
||||
///
|
||||
void Run(const std::string& group, const std::string& experiment);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
315
celero/celero/Experiment.cpp
Normal file
315
celero/celero/Experiment.cpp
Normal file
@ -0,0 +1,315 @@
|
||||
///
|
||||
/// \author John Farrier
|
||||
///
|
||||
/// \copyright Copyright 2015, 2016, 2017, 2018 John Farrier
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
|
||||
#include <celero/Experiment.h>
|
||||
#include <celero/Factory.h>
|
||||
#include <celero/PimplImpl.h>
|
||||
#include <celero/TestFixture.h>
|
||||
#include <celero/TestVector.h>
|
||||
#include <celero/Utilities.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
|
||||
using namespace celero;
|
||||
|
||||
class Experiment::Impl
|
||||
{
|
||||
public:
|
||||
Impl() :
|
||||
results(),
|
||||
benchmark(),
|
||||
factory(),
|
||||
name(),
|
||||
baselineUnit(0),
|
||||
baselineTarget(0),
|
||||
samples(0),
|
||||
iterations(0),
|
||||
threads(1),
|
||||
totalRunTime(0),
|
||||
isBaselineCase(false)
|
||||
{
|
||||
}
|
||||
|
||||
Impl(std::weak_ptr<Benchmark> bm, const std::string& n, const uint64_t s, const uint64_t c, const uint64_t t, const double pBaselineTarget) :
|
||||
results(),
|
||||
benchmark(bm),
|
||||
factory(),
|
||||
name(n),
|
||||
baselineUnit(0),
|
||||
baselineTarget(pBaselineTarget),
|
||||
samples(s),
|
||||
iterations(c),
|
||||
threads(t),
|
||||
totalRunTime(0),
|
||||
isBaselineCase(false)
|
||||
{
|
||||
}
|
||||
|
||||
Impl(std::weak_ptr<Benchmark> bm) :
|
||||
results(),
|
||||
benchmark(bm),
|
||||
factory(),
|
||||
name(),
|
||||
baselineUnit(0),
|
||||
baselineTarget(0),
|
||||
samples(0),
|
||||
iterations(0),
|
||||
threads(1),
|
||||
totalRunTime(0),
|
||||
isBaselineCase(false)
|
||||
{
|
||||
}
|
||||
|
||||
/// There is one result for each problem space value.
|
||||
/// In the event there are not any problem spaces, there shal be a single result.
|
||||
std::vector<std::shared_ptr<celero::ExperimentResult>> results;
|
||||
|
||||
/// The owning benchmark object which groups together all experiments.
|
||||
std::weak_ptr<Benchmark> benchmark;
|
||||
|
||||
/// The factory to associate with this benchmark.
|
||||
std::shared_ptr<Factory> factory;
|
||||
|
||||
/// The name of this experiment.
|
||||
std::string name;
|
||||
|
||||
/// The number of microseconds per test (which makes up one baseline unit).
|
||||
double baselineUnit;
|
||||
|
||||
/// Used to pass/fail benchmarks when outputting JUnit.
|
||||
double baselineTarget;
|
||||
|
||||
/// Test samples to complete.
|
||||
uint64_t samples;
|
||||
|
||||
/// Iterations per test run. (Size of each sample.)
|
||||
uint64_t iterations;
|
||||
|
||||
/// Threads per test run.
|
||||
uint64_t threads;
|
||||
|
||||
/// The best run time for this test
|
||||
uint64_t totalRunTime;
|
||||
|
||||
bool isBaselineCase;
|
||||
};
|
||||
|
||||
Experiment::Experiment() : pimpl()
|
||||
{
|
||||
}
|
||||
|
||||
Experiment::Experiment(std::weak_ptr<Benchmark> benchmark) : pimpl(benchmark)
|
||||
{
|
||||
}
|
||||
|
||||
Experiment::Experiment(std::weak_ptr<Benchmark> benchmark, const std::string& name, uint64_t samples, uint64_t iterations, uint64_t threads,
|
||||
double baselineTarget) :
|
||||
pimpl(benchmark, name, samples, iterations, threads, baselineTarget)
|
||||
{
|
||||
}
|
||||
|
||||
Experiment::Experiment(const Experiment&)
|
||||
{
|
||||
}
|
||||
|
||||
Experiment::~Experiment()
|
||||
{
|
||||
}
|
||||
|
||||
std::shared_ptr<Benchmark> Experiment::getBenchmark()
|
||||
{
|
||||
return this->pimpl->benchmark.lock();
|
||||
}
|
||||
|
||||
void Experiment::setName(const std::string& x)
|
||||
{
|
||||
this->pimpl->name = x;
|
||||
}
|
||||
|
||||
std::string Experiment::getName() const
|
||||
{
|
||||
return this->pimpl->name;
|
||||
}
|
||||
|
||||
void Experiment::setSamples(uint64_t x)
|
||||
{
|
||||
this->pimpl->samples = x;
|
||||
}
|
||||
|
||||
uint64_t Experiment::getSamples() const
|
||||
{
|
||||
return this->pimpl->samples;
|
||||
}
|
||||
|
||||
void Experiment::setIterations(uint64_t x)
|
||||
{
|
||||
this->pimpl->iterations = x;
|
||||
}
|
||||
|
||||
uint64_t Experiment::getIterations() const
|
||||
{
|
||||
return this->pimpl->iterations;
|
||||
}
|
||||
|
||||
void Experiment::setThreads(uint64_t x)
|
||||
{
|
||||
this->pimpl->threads = x;
|
||||
}
|
||||
|
||||
uint64_t Experiment::getThreads() const
|
||||
{
|
||||
return this->pimpl->threads;
|
||||
}
|
||||
|
||||
Experiment::operator std::string() const
|
||||
{
|
||||
auto output = this->getShort();
|
||||
|
||||
if(this->getSamples() > 0)
|
||||
{
|
||||
output += " -- " + std::to_string(this->getSamples());
|
||||
|
||||
if(this->getSamples() == 1)
|
||||
{
|
||||
output += " run, ";
|
||||
}
|
||||
else
|
||||
{
|
||||
output += " samples, ";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
output += " -- Auto Run, ";
|
||||
}
|
||||
|
||||
output += std::to_string(this->getIterations());
|
||||
|
||||
if(this->getIterations() == 1)
|
||||
{
|
||||
output += " iteration per run,";
|
||||
}
|
||||
else
|
||||
{
|
||||
output += " iterations per run,";
|
||||
}
|
||||
|
||||
if(this->getThreads() == 1)
|
||||
{
|
||||
output += " thread per run.";
|
||||
}
|
||||
else
|
||||
{
|
||||
output += " threads per run.";
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
std::string Experiment::getShort() const
|
||||
{
|
||||
auto bm = this->pimpl->benchmark.lock();
|
||||
|
||||
if(bm != nullptr)
|
||||
{
|
||||
return bm->getName() + "." + this->getName();
|
||||
}
|
||||
|
||||
return this->getName();
|
||||
}
|
||||
|
||||
void Experiment::setBaselineTarget(double x)
|
||||
{
|
||||
this->pimpl->baselineTarget = x;
|
||||
}
|
||||
|
||||
double Experiment::getBaselineTarget() const
|
||||
{
|
||||
return this->pimpl->baselineTarget;
|
||||
}
|
||||
|
||||
void Experiment::incrementTotalRunTime(const uint64_t x)
|
||||
{
|
||||
this->pimpl->totalRunTime += x;
|
||||
}
|
||||
|
||||
uint64_t Experiment::getTotalRunTime() const
|
||||
{
|
||||
return this->pimpl->totalRunTime;
|
||||
}
|
||||
|
||||
void Experiment::setIsBaselineCase(bool x)
|
||||
{
|
||||
this->pimpl->isBaselineCase = x;
|
||||
}
|
||||
|
||||
bool Experiment::getIsBaselineCase() const
|
||||
{
|
||||
return this->pimpl->isBaselineCase;
|
||||
}
|
||||
|
||||
void Experiment::setFactory(std::shared_ptr<Factory> x)
|
||||
{
|
||||
this->pimpl->factory = x;
|
||||
}
|
||||
|
||||
std::shared_ptr<Factory> Experiment::getFactory() const
|
||||
{
|
||||
return this->pimpl->factory;
|
||||
}
|
||||
|
||||
void Experiment::addProblemSpace(int64_t x, double scale, uint64_t iterations)
|
||||
{
|
||||
auto r = std::make_shared<celero::ExperimentResult>(this);
|
||||
r->setProblemSpaceValue(x, scale, iterations);
|
||||
this->pimpl->results.push_back(r);
|
||||
}
|
||||
|
||||
size_t Experiment::getResultSize()
|
||||
{
|
||||
if(this->pimpl->results.empty() == true)
|
||||
{
|
||||
auto defaultResult = std::make_shared<celero::ExperimentResult>(this);
|
||||
defaultResult->setProblemSpaceValue(static_cast<int64_t>(TestFixture::Constants::NoProblemSpaceValue), 1.0, this->getIterations());
|
||||
this->pimpl->results.push_back(defaultResult);
|
||||
}
|
||||
|
||||
return this->pimpl->results.size();
|
||||
}
|
||||
|
||||
std::shared_ptr<celero::ExperimentResult> Experiment::getResult(size_t x)
|
||||
{
|
||||
// get the result OR thrown an exception if the result list is empty;
|
||||
return this->pimpl->results.at(x);
|
||||
}
|
||||
|
||||
std::shared_ptr<celero::ExperimentResult> Experiment::getResultByValue(int64_t x)
|
||||
{
|
||||
std::shared_ptr<celero::ExperimentResult> r;
|
||||
|
||||
const auto found = std::find_if(std::begin(this->pimpl->results), std::end(this->pimpl->results),
|
||||
[x](std::shared_ptr<celero::ExperimentResult> i) -> bool { return (i->getProblemSpaceValue() == x); });
|
||||
|
||||
if(found != std::end(this->pimpl->results))
|
||||
{
|
||||
r = (*found);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
196
celero/celero/Experiment.h
Normal file
196
celero/celero/Experiment.h
Normal file
@ -0,0 +1,196 @@
|
||||
#ifndef H_CELERO_EXPERIMENT_H
|
||||
#define H_CELERO_EXPERIMENT_H
|
||||
|
||||
///
|
||||
/// \author John Farrier
|
||||
///
|
||||
/// \copyright Copyright 2015, 2016, 2017, 2018 John Farrier
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
|
||||
#include <celero/ExperimentResult.h>
|
||||
#include <celero/Factory.h>
|
||||
#include <celero/Statistics.h>
|
||||
#include <string>
|
||||
|
||||
namespace celero
|
||||
{
|
||||
class Benchmark;
|
||||
|
||||
///
|
||||
/// \class Experiment
|
||||
///
|
||||
/// \author John Farrier
|
||||
///
|
||||
class CELERO_EXPORT Experiment
|
||||
{
|
||||
public:
|
||||
///
|
||||
///
|
||||
///
|
||||
explicit Experiment(std::weak_ptr<Benchmark> benchmark);
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
explicit Experiment(std::weak_ptr<Benchmark> benchmark, const std::string& name, uint64_t samples, uint64_t iterations, uint64_t threads,
|
||||
double baselineTarget);
|
||||
|
||||
///
|
||||
/// \brief Default destructor.
|
||||
///
|
||||
~Experiment();
|
||||
|
||||
///
|
||||
/// Gets a pointer to the owning Benchmark object.
|
||||
///
|
||||
std::shared_ptr<Benchmark> getBenchmark();
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
void setName(const std::string& x);
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
std::string getName() const;
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
void setSamples(uint64_t x);
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
uint64_t getSamples() const;
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
void setIterations(uint64_t x);
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
uint64_t getIterations() const;
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
void setThreads(uint64_t x);
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
uint64_t getThreads() const;
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
operator std::string() const;
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
std::string getShort() const;
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
void setBaselineTarget(double x);
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
double getBaselineTarget() const;
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
void incrementTotalRunTime(const uint64_t x);
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
uint64_t getTotalRunTime() const;
|
||||
|
||||
///
|
||||
/// Used to set a flag indicating that this is a Baseline case, not a benchmark case.
|
||||
///
|
||||
void setIsBaselineCase(bool x);
|
||||
|
||||
///
|
||||
/// Used to get a flag indicating that this is a Baseline case, not a benchmark case.
|
||||
///
|
||||
bool getIsBaselineCase() const;
|
||||
|
||||
///
|
||||
/// Sets the factory used to create this experiment's test fixtures.
|
||||
///
|
||||
void setFactory(std::shared_ptr<Factory> x);
|
||||
|
||||
///
|
||||
/// Gets the factory used to create this experiment's test fixtures.
|
||||
///
|
||||
std::shared_ptr<Factory> getFactory() const;
|
||||
|
||||
///
|
||||
/// \param x Can be interpreted in any way be the test fixture (i.e. index into an array, etc.)
|
||||
/// \param scale Used to format unit results.
|
||||
/// \param iterations Override the default iterations with the number here when greater than zero.
|
||||
///
|
||||
void addProblemSpace(int64_t x, double scale = 1.0, uint64_t iterations = 0);
|
||||
|
||||
///
|
||||
/// There is one result for each problem space.
|
||||
///
|
||||
size_t getResultSize();
|
||||
|
||||
///
|
||||
/// Get an ExperimentResult at a given index.
|
||||
///
|
||||
std::shared_ptr<celero::ExperimentResult> getResult(size_t x);
|
||||
|
||||
///
|
||||
/// Get the ExperimentResult for the given problem space value.
|
||||
///
|
||||
std::shared_ptr<celero::ExperimentResult> getResultByValue(int64_t x);
|
||||
|
||||
private:
|
||||
///
|
||||
/// Hide the default constructor
|
||||
///
|
||||
Experiment();
|
||||
|
||||
///
|
||||
/// Hide the copy constructor
|
||||
///
|
||||
explicit Experiment(const Experiment&);
|
||||
|
||||
///
|
||||
///
|
||||
/// \brief Pimpl Idiom
|
||||
///
|
||||
class Impl;
|
||||
|
||||
///
|
||||
/// \brief Pimpl Idiom
|
||||
///
|
||||
Pimpl<Impl> pimpl;
|
||||
};
|
||||
} // namespace celero
|
||||
|
||||
#endif
|
206
celero/celero/ExperimentResult.cpp
Normal file
206
celero/celero/ExperimentResult.cpp
Normal file
@ -0,0 +1,206 @@
|
||||
///
|
||||
/// \author John Farrier
|
||||
///
|
||||
/// \copyright Copyright 2015, 2016, 2017, 2018 John Farrier
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
|
||||
#include <celero/Benchmark.h>
|
||||
#include <celero/Experiment.h>
|
||||
#include <celero/ExperimentResult.h>
|
||||
#include <celero/PimplImpl.h>
|
||||
#include <celero/Statistics.h>
|
||||
#include <celero/Timer.h>
|
||||
#include <celero/UserDefinedMeasurementCollector.h>
|
||||
#include <celero/Utilities.h>
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
|
||||
using namespace celero;
|
||||
|
||||
class ExperimentResult::Impl
|
||||
{
|
||||
public:
|
||||
Impl()
|
||||
{
|
||||
}
|
||||
|
||||
explicit Impl(Experiment* const p) : parent(p)
|
||||
{
|
||||
}
|
||||
|
||||
/// Track statistics related to execution time about this specific experiment.
|
||||
Statistics<int64_t> statsTime;
|
||||
Statistics<int64_t> statsRAM;
|
||||
|
||||
std::shared_ptr<UserDefinedMeasurementCollector> udmCollector;
|
||||
|
||||
int64_t problemSpaceValue{0};
|
||||
double problemSpaceValueScale{1.0};
|
||||
uint64_t problemSpaceIterations{0};
|
||||
|
||||
/// A pointer back to our owning Experiment parent.
|
||||
Experiment* parent{nullptr};
|
||||
|
||||
/// A "completed" flag.
|
||||
bool complete{false};
|
||||
|
||||
/// A "failure" flag.
|
||||
bool failure{false};
|
||||
};
|
||||
|
||||
ExperimentResult::ExperimentResult()
|
||||
{
|
||||
}
|
||||
|
||||
ExperimentResult::ExperimentResult(Experiment* x) : pimpl(x)
|
||||
{
|
||||
}
|
||||
|
||||
ExperimentResult::~ExperimentResult()
|
||||
{
|
||||
}
|
||||
|
||||
Experiment* ExperimentResult::getExperiment() const
|
||||
{
|
||||
return this->pimpl->parent;
|
||||
}
|
||||
|
||||
void ExperimentResult::setProblemSpaceValue(int64_t x, double scale, uint64_t iterations)
|
||||
{
|
||||
this->pimpl->problemSpaceValue = x;
|
||||
this->pimpl->problemSpaceValueScale = scale;
|
||||
this->pimpl->problemSpaceIterations = iterations;
|
||||
}
|
||||
|
||||
int64_t ExperimentResult::getProblemSpaceValue() const
|
||||
{
|
||||
return this->pimpl->problemSpaceValue;
|
||||
}
|
||||
|
||||
double ExperimentResult::getProblemSpaceValueScale() const
|
||||
{
|
||||
return this->pimpl->problemSpaceValueScale;
|
||||
}
|
||||
|
||||
uint64_t ExperimentResult::getProblemSpaceIterations() const
|
||||
{
|
||||
return this->pimpl->problemSpaceIterations;
|
||||
}
|
||||
|
||||
Statistics<int64_t>* ExperimentResult::getTimeStatistics()
|
||||
{
|
||||
return &this->pimpl->statsTime;
|
||||
}
|
||||
|
||||
void ExperimentResult::addRunTimeSample(const uint64_t runTime)
|
||||
{
|
||||
this->pimpl->statsTime.addSample(runTime);
|
||||
}
|
||||
|
||||
uint64_t ExperimentResult::getRunTime() const
|
||||
{
|
||||
return this->pimpl->statsTime.getMin();
|
||||
}
|
||||
|
||||
double ExperimentResult::getUsPerCall() const
|
||||
{
|
||||
if(this->pimpl->failure == false)
|
||||
{
|
||||
return static_cast<double>(this->pimpl->statsTime.getMin()) / static_cast<double>(this->pimpl->problemSpaceIterations);
|
||||
}
|
||||
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
double ExperimentResult::getCallsPerSecond() const
|
||||
{
|
||||
if(this->pimpl->failure == false)
|
||||
{
|
||||
return 1.0 / (this->getUsPerCall() * celero::UsToSec);
|
||||
}
|
||||
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
double ExperimentResult::getUnitsPerSecond() const
|
||||
{
|
||||
return (this->pimpl->problemSpaceValueScale > 0.0)
|
||||
? ((this->pimpl->problemSpaceValue * this->pimpl->problemSpaceIterations / this->pimpl->problemSpaceValueScale)
|
||||
/ (this->pimpl->statsTime.getMin() * celero::UsToSec))
|
||||
: 0.0;
|
||||
}
|
||||
|
||||
double ExperimentResult::getBaselineMeasurement() const
|
||||
{
|
||||
if(this->pimpl->parent->getIsBaselineCase() == false)
|
||||
{
|
||||
const auto bm = this->pimpl->parent->getBenchmark();
|
||||
|
||||
if(bm != nullptr)
|
||||
{
|
||||
const auto baselineExperiment = bm->getBaseline();
|
||||
|
||||
if(baselineExperiment != nullptr)
|
||||
{
|
||||
const auto baselineResult = baselineExperiment->getResultByValue(this->getProblemSpaceValue());
|
||||
|
||||
if(baselineResult != nullptr)
|
||||
{
|
||||
const auto baselineResultUs = baselineResult->getUsPerCall();
|
||||
|
||||
// Prevent possible divide by zero.
|
||||
if(baselineResultUs > 0)
|
||||
{
|
||||
return this->getUsPerCall() / baselineResult->getUsPerCall();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1.0;
|
||||
}
|
||||
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
void ExperimentResult::setComplete(bool x)
|
||||
{
|
||||
this->pimpl->complete = x;
|
||||
}
|
||||
|
||||
bool ExperimentResult::getComplete() const
|
||||
{
|
||||
return this->pimpl->complete;
|
||||
}
|
||||
|
||||
void ExperimentResult::setFailure(bool x)
|
||||
{
|
||||
this->pimpl->failure = x;
|
||||
}
|
||||
|
||||
bool ExperimentResult::getFailure() const
|
||||
{
|
||||
return this->pimpl->failure;
|
||||
}
|
||||
|
||||
void ExperimentResult::setUserDefinedMeasurements(std::shared_ptr<UserDefinedMeasurementCollector> x)
|
||||
{
|
||||
this->pimpl->udmCollector = x;
|
||||
}
|
||||
|
||||
std::shared_ptr<UserDefinedMeasurementCollector> ExperimentResult::getUserDefinedMeasurements() const
|
||||
{
|
||||
return this->pimpl->udmCollector;
|
||||
}
|
161
celero/celero/ExperimentResult.h
Normal file
161
celero/celero/ExperimentResult.h
Normal file
@ -0,0 +1,161 @@
|
||||
#ifndef H_CELERO_EXPERIMENTRESULT_H
|
||||
#define H_CELERO_EXPERIMENTRESULT_H
|
||||
|
||||
///
|
||||
/// \author John Farrier
|
||||
///
|
||||
/// \copyright Copyright 2015, 2016, 2017, 2018 John Farrier
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
|
||||
#include <celero/Export.h>
|
||||
#include <celero/Pimpl.h>
|
||||
#include <celero/Statistics.h>
|
||||
#include <string>
|
||||
|
||||
namespace celero
|
||||
{
|
||||
class Experiment;
|
||||
class UserDefinedMeasurementCollector;
|
||||
|
||||
///
|
||||
/// \class ExperimentResult
|
||||
///
|
||||
/// \author John Farrier
|
||||
///
|
||||
class CELERO_EXPORT ExperimentResult
|
||||
{
|
||||
public:
|
||||
explicit ExperimentResult(Experiment* x);
|
||||
|
||||
~ExperimentResult();
|
||||
|
||||
///
|
||||
/// Gets a pointer to the owning experiment.
|
||||
///
|
||||
Experiment* getExperiment() const;
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
void setProblemSpaceValue(int64_t x, double scale = 1.0, uint64_t iterations = 0);
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
int64_t getProblemSpaceValue() const;
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
double getProblemSpaceValueScale() const;
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
uint64_t getProblemSpaceIterations() const;
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Statistics<int64_t>* getTimeStatistics();
|
||||
|
||||
///
|
||||
/// Adds a run time sample during experiment execution.
|
||||
///
|
||||
void addRunTimeSample(const uint64_t x);
|
||||
|
||||
///
|
||||
/// Returns the best run time sample observed.
|
||||
///
|
||||
uint64_t getRunTime() const;
|
||||
|
||||
///
|
||||
/// \brief Get the number of computed microseconds per iteration (i.e. a single call to the code under test.)
|
||||
///
|
||||
/// A call is defined as one iteration of one execution of the code under test.
|
||||
///
|
||||
double getUsPerCall() const;
|
||||
|
||||
///
|
||||
/// \brief Get the number of times the code under test could be called per second.
|
||||
///
|
||||
/// A call is defined as one iteration of one execution of the code under test.
|
||||
///
|
||||
double getCallsPerSecond() const;
|
||||
|
||||
///
|
||||
/// \brief Get the processing speed in units per second.
|
||||
///
|
||||
/// A call is defined as one iteration of one execution of the code under test.
|
||||
///
|
||||
double getUnitsPerSecond() const;
|
||||
|
||||
///
|
||||
/// Calculate this experiments baseline value.
|
||||
///
|
||||
/// If this IS a baseline experiment, the function will return 1.0;
|
||||
/// Returns -1 on error.
|
||||
///
|
||||
double getBaselineMeasurement() const;
|
||||
|
||||
///
|
||||
/// Sets a flag indicating if this result is complete.
|
||||
///
|
||||
void setComplete(bool x);
|
||||
|
||||
///
|
||||
/// Gets a flag indicating if this result is complete.
|
||||
///
|
||||
bool getComplete() const;
|
||||
|
||||
///
|
||||
/// Sets a flag indicating if failure happened during evaluation.
|
||||
///
|
||||
void setFailure(bool x);
|
||||
|
||||
///
|
||||
/// Gets a flag indicating if failure happened during evaluation.
|
||||
///
|
||||
bool getFailure() const;
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
void setUserDefinedMeasurements(std::shared_ptr<UserDefinedMeasurementCollector> x);
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
std::shared_ptr<UserDefinedMeasurementCollector> getUserDefinedMeasurements() const;
|
||||
|
||||
private:
|
||||
///
|
||||
/// Disable default constructor
|
||||
///
|
||||
ExperimentResult();
|
||||
|
||||
///
|
||||
/// \brief Pimpl Idiom
|
||||
///
|
||||
class Impl;
|
||||
|
||||
///
|
||||
/// \brief Pimpl Idiom
|
||||
///
|
||||
Pimpl<Impl> pimpl;
|
||||
};
|
||||
} // namespace celero
|
||||
|
||||
#endif
|
40
celero/celero/Export.h
Normal file
40
celero/celero/Export.h
Normal file
@ -0,0 +1,40 @@
|
||||
#ifndef H_CELERO_EXPORT_H
|
||||
#define H_CELERO_EXPORT_H
|
||||
|
||||
///
|
||||
/// \author John Farrier
|
||||
///
|
||||
/// \copyright Copyright 2015, 2016, 2017, 2018 John Farrier
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
|
||||
#ifdef CELERO_STATIC
|
||||
#define CELERO_EXPORT
|
||||
#define CELERO_EXPORT_C
|
||||
#else
|
||||
#ifdef WIN32
|
||||
#if defined CELERO_EXPORTS
|
||||
#define CELERO_EXPORT _declspec(dllexport)
|
||||
#define CELERO_EXPORT_C extern "C" _declspec(dllexport)
|
||||
#else
|
||||
#define CELERO_EXPORT _declspec(dllimport)
|
||||
#define CELERO_EXPORT_C extern "C" _declspec(dllimport)
|
||||
#endif
|
||||
#else
|
||||
#define CELERO_EXPORT
|
||||
#define CELERO_EXPORT_C extern "C"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif
|
59
celero/celero/Factory.h
Normal file
59
celero/celero/Factory.h
Normal file
@ -0,0 +1,59 @@
|
||||
#ifndef H_CELERO_FACTORY_H
|
||||
#define H_CELERO_FACTORY_H
|
||||
|
||||
///
|
||||
/// \author John Farrier
|
||||
///
|
||||
/// \copyright Copyright 2015, 2016, 2017, 2018 John Farrier
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
|
||||
#include <celero/Export.h>
|
||||
#include <celero/TestFixture.h>
|
||||
#include <memory>
|
||||
|
||||
namespace celero
|
||||
{
|
||||
///
|
||||
/// \class Factory
|
||||
///
|
||||
/// \author John Farrier
|
||||
///
|
||||
/// Pure Virtual Base class for benchmarks.
|
||||
///
|
||||
class CELERO_EXPORT Factory
|
||||
{
|
||||
public:
|
||||
///
|
||||
/// \brief Default Constructor
|
||||
///
|
||||
Factory()
|
||||
{
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Virtual Destructor
|
||||
///
|
||||
virtual ~Factory()
|
||||
{
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Pure virtual function.
|
||||
///
|
||||
virtual std::shared_ptr<TestFixture> Create() = 0;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
50
celero/celero/FileReader.h
Normal file
50
celero/celero/FileReader.h
Normal file
@ -0,0 +1,50 @@
|
||||
#ifndef H_CELERO_FILEREADER_H
|
||||
#define H_CELERO_FILEREADER_H
|
||||
|
||||
///
|
||||
/// \author John Farrier
|
||||
///
|
||||
/// \copyright Copyright 2015, 2016, 2017, 2018 John Farrier
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
|
||||
#include <locale>
|
||||
|
||||
namespace celero
|
||||
{
|
||||
///
|
||||
/// \struct FileReader
|
||||
///
|
||||
/// A helper struct to aid in reading CSV files.
|
||||
///
|
||||
/// Classify commas as whitespace.
|
||||
///
|
||||
struct FieldReader : std::ctype<char>
|
||||
{
|
||||
FieldReader() : std::ctype<char>(FieldReader::GetTable())
|
||||
{
|
||||
}
|
||||
|
||||
static std::ctype_base::mask const* GetTable()
|
||||
{
|
||||
static std::vector<std::ctype_base::mask> rc(table_size, std::ctype_base::mask());
|
||||
rc[','] = std::ctype_base::space;
|
||||
rc['\n'] = std::ctype_base::space;
|
||||
rc['\r'] = std::ctype_base::space;
|
||||
return &rc[0];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
60
celero/celero/GenericFactory.h
Normal file
60
celero/celero/GenericFactory.h
Normal file
@ -0,0 +1,60 @@
|
||||
#ifndef H_CELERO_GENERICFACTORY_H
|
||||
#define H_CELERO_GENERICFACTORY_H
|
||||
|
||||
///
|
||||
/// \author John Farrier
|
||||
///
|
||||
/// \copyright Copyright 2015, 2016, 2017, 2018 John Farrier
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
|
||||
#include <celero/Export.h>
|
||||
#include <celero/Factory.h>
|
||||
|
||||
namespace celero
|
||||
{
|
||||
///
|
||||
/// \class GenericFactory
|
||||
///
|
||||
/// \author John farrier
|
||||
///
|
||||
template <class T>
|
||||
class GenericFactory : public Factory
|
||||
{
|
||||
public:
|
||||
///
|
||||
/// \brief Default Constructor
|
||||
///
|
||||
GenericFactory() : Factory()
|
||||
{
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Virtual Destructor
|
||||
///
|
||||
virtual ~GenericFactory()
|
||||
{
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Overload the pure virtual base class function.
|
||||
///
|
||||
virtual std::shared_ptr<TestFixture> Create()
|
||||
{
|
||||
return std::make_shared<T>();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
149
celero/celero/JUnit.cpp
Normal file
149
celero/celero/JUnit.cpp
Normal file
@ -0,0 +1,149 @@
|
||||
///
|
||||
/// \author John Farrier
|
||||
///
|
||||
/// \copyright Copyright 2015, 2016, 2017, 2018 John Farrier
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
|
||||
#include <assert.h>
|
||||
#include <celero/Benchmark.h>
|
||||
#include <celero/JUnit.h>
|
||||
#include <celero/PimplImpl.h>
|
||||
#include <celero/Timer.h>
|
||||
#include <celero/Utilities.h>
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
using namespace celero;
|
||||
|
||||
///
|
||||
/// \struct celero::JUnit::Impl
|
||||
///
|
||||
class celero::JUnit::Impl
|
||||
{
|
||||
public:
|
||||
std::string fileName;
|
||||
|
||||
/// Store the test case size, measured baseline, objective baseline, and total run time in seconds.
|
||||
std::map<std::string, std::vector<std::shared_ptr<celero::ExperimentResult>>> results;
|
||||
|
||||
double totalTime = {0.0};
|
||||
};
|
||||
|
||||
JUnit& JUnit::Instance()
|
||||
{
|
||||
static JUnit singleton;
|
||||
return singleton;
|
||||
}
|
||||
|
||||
void JUnit::setFileName(const std::string& x)
|
||||
{
|
||||
assert(x.empty() == false);
|
||||
this->pimpl->fileName = x;
|
||||
}
|
||||
|
||||
void JUnit::add(std::shared_ptr<celero::ExperimentResult> x)
|
||||
{
|
||||
this->pimpl->results[x->getExperiment()->getBenchmark()->getName()].push_back(x);
|
||||
this->save();
|
||||
}
|
||||
|
||||
void JUnit::save()
|
||||
{
|
||||
std::ofstream ofs;
|
||||
ofs.open(this->pimpl->fileName);
|
||||
|
||||
if(ofs.is_open() == true)
|
||||
{
|
||||
const auto os = &ofs;
|
||||
|
||||
*os << "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>" << std::endl;
|
||||
|
||||
for(auto i : this->pimpl->results)
|
||||
{
|
||||
uint64_t testSuiteTime = 0;
|
||||
size_t testSuiteFailures = 0;
|
||||
size_t testSuiteErrors = 0;
|
||||
|
||||
const auto runs = i.second;
|
||||
|
||||
for(auto j : runs)
|
||||
{
|
||||
if(j->getFailure())
|
||||
{
|
||||
testSuiteErrors++;
|
||||
continue;
|
||||
}
|
||||
else if((j->getExperiment()->getBaselineTarget() > 0.0) && (j->getBaselineMeasurement() > j->getExperiment()->getBaselineTarget()))
|
||||
{
|
||||
testSuiteFailures++;
|
||||
}
|
||||
|
||||
testSuiteTime += j->getRunTime();
|
||||
}
|
||||
|
||||
*os << "<testsuite errors=\"" << testSuiteErrors << "\" ";
|
||||
*os << "tests=\"" << i.second.size() << "\" ";
|
||||
*os << "time=\"" << celero::timer::ConvertSystemTime(testSuiteTime) << "\" ";
|
||||
*os << "failures=\"" << testSuiteFailures << "\" ";
|
||||
*os << "name=\"" << i.first << "\">" << std::endl;
|
||||
|
||||
for(auto j : runs)
|
||||
{
|
||||
*os << "\t<testcase ";
|
||||
*os << "time=\"" << celero::timer::ConvertSystemTime(j->getFailure() ? 0 : j->getRunTime()) << "\" ";
|
||||
*os << "name=\"" << j->getExperiment()->getName() << "#" << j->getProblemSpaceValue() << "\"";
|
||||
|
||||
// Compare measured to objective
|
||||
if(j->getFailure())
|
||||
{
|
||||
// Error
|
||||
*os << ">" << std::endl;
|
||||
|
||||
*os << "\t\t<error ";
|
||||
*os << "type=\"exception\"";
|
||||
*os << "/>" << std::endl;
|
||||
|
||||
*os << "\t</testcase>" << std::endl;
|
||||
}
|
||||
else if((j->getExperiment()->getBaselineTarget() > 0.0) && (j->getBaselineMeasurement() > j->getExperiment()->getBaselineTarget()))
|
||||
{
|
||||
// Failure
|
||||
*os << ">" << std::endl;
|
||||
|
||||
*os << "\t\t<failure ";
|
||||
*os << "type=\"Performance objective not met.\" ";
|
||||
*os << "message=\"Measurement of " << j->getBaselineMeasurement() << " exceeds objective baseline of "
|
||||
<< j->getExperiment()->getBaselineTarget() << "\" ";
|
||||
*os << "/>" << std::endl;
|
||||
|
||||
*os << "\t</testcase>" << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Success
|
||||
*os << "/>" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
*os << "</testsuite>" << std::endl;
|
||||
}
|
||||
|
||||
ofs.close();
|
||||
}
|
||||
}
|
73
celero/celero/JUnit.h
Normal file
73
celero/celero/JUnit.h
Normal file
@ -0,0 +1,73 @@
|
||||
#ifndef H_CELERO_JUNIT_H
|
||||
#define H_CELERO_JUNIT_H
|
||||
|
||||
///
|
||||
/// \author John Farrier
|
||||
///
|
||||
/// \copyright Copyright 2015, 2016, 2017, 2018 John Farrier
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
|
||||
#include <celero/Experiment.h>
|
||||
#include <celero/Pimpl.h>
|
||||
#include <string>
|
||||
|
||||
namespace celero
|
||||
{
|
||||
///
|
||||
/// \class JUnit
|
||||
///
|
||||
/// \author John Farrier
|
||||
///
|
||||
class JUnit
|
||||
{
|
||||
public:
|
||||
///
|
||||
/// Singleton
|
||||
///
|
||||
static JUnit& Instance();
|
||||
|
||||
///
|
||||
/// Specify a file name for a results output file.
|
||||
///
|
||||
/// \param x The name of the output file in which to store Celero's results.
|
||||
///
|
||||
void setFileName(const std::string& x);
|
||||
|
||||
///
|
||||
/// Add a new result to the JUnit output XML.
|
||||
///
|
||||
/// This should re-save on every new result so that the output can be monitored externally.
|
||||
///
|
||||
void add(std::shared_ptr<celero::ExperimentResult> x);
|
||||
|
||||
///
|
||||
/// Save the JUnit (XUnit) formatted file to the given file name.
|
||||
///
|
||||
void save();
|
||||
|
||||
private:
|
||||
///
|
||||
/// \brief Pimpl Idiom
|
||||
///
|
||||
class Impl;
|
||||
|
||||
///
|
||||
/// \brief Pimpl Idiom
|
||||
///
|
||||
Pimpl<Impl> pimpl;
|
||||
};
|
||||
} // namespace celero
|
||||
|
||||
#endif
|
392
celero/celero/Memory.cpp
Normal file
392
celero/celero/Memory.cpp
Normal file
@ -0,0 +1,392 @@
|
||||
///
|
||||
/// \author John Farrier
|
||||
///
|
||||
/// \copyright Copyright 2015, 2016, 2017, 2018 John Farrier
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
|
||||
#include <celero/Memory.h>
|
||||
#include <sstream>
|
||||
|
||||
#ifdef WIN32
|
||||
#include <Windows.h>
|
||||
|
||||
#include <Psapi.h>
|
||||
#elif defined(__APPLE__)
|
||||
#include <sys/param.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <array>
|
||||
#else
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/sysinfo.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
///
|
||||
/// References:
|
||||
/// http://blogs.microsoft.co.il/sasha/2016/01/05/windows-process-memory-usage-demystified/
|
||||
/// https://msdn.microsoft.com/en-us/library/windows/desktop/aa366770(v=vs.85).aspx
|
||||
/// https://msdn.microsoft.com/en-us/library/windows/desktop/ms684877(v=vs.85).aspx
|
||||
/// http://nadeausoftware.com/articles/2012/09/c_c_tip_how_get_physical_memory_size_system
|
||||
/// http://nadeausoftware.com/articles/2012/07/c_c_tip_how_get_process_resident_set_size_physical_memory_use
|
||||
/// https://stackoverflow.com/questions/669438/how-to-get-memory-usage-at-run-time-in-c
|
||||
/// https://stackoverflow.com/questions/2513505/how-to-get-available-memory-c-g
|
||||
///
|
||||
|
||||
using namespace celero;
|
||||
|
||||
constexpr int64_t Kilobytes2Bytes{1024};
|
||||
|
||||
#ifdef WIN32
|
||||
#else
|
||||
namespace celero
|
||||
{
|
||||
namespace impl
|
||||
{
|
||||
int ParseLine(char* line)
|
||||
{
|
||||
const auto i = strlen(line);
|
||||
|
||||
while(*line < '0' || *line > '9')
|
||||
{
|
||||
line++;
|
||||
}
|
||||
|
||||
line[i - 3] = '\0';
|
||||
return atoi(line);
|
||||
}
|
||||
} // namespace impl
|
||||
} // namespace celero
|
||||
#endif
|
||||
|
||||
celero::RAMReport::operator std::string()
|
||||
{
|
||||
std::stringstream ss;
|
||||
|
||||
ss << "System Total: " << this->RamSystemTotal << std::endl;
|
||||
ss << "System Available: " << this->RamSystemAvailable << std::endl;
|
||||
ss << "System Used: " << this->RamSystemUsed << std::endl;
|
||||
ss << "System UsedByCurrentProcess: " << this->RamSystemUsedByCurrentProcess << std::endl;
|
||||
ss << "Physical Total: " << this->RamPhysicalTotal << std::endl;
|
||||
ss << "Physical Available: " << this->RamPhysicalAvailable << std::endl;
|
||||
ss << "Physical Used: " << this->RamPhysicalUsed << std::endl;
|
||||
ss << "Physical UsedByCurrentProcess: " << this->RamPhysicalUsedByCurrentProcess << std::endl;
|
||||
ss << "Physical UsedByCurrentProcessPeak: " << this->RamPhysicalUsedByCurrentProcessPeak << std::endl;
|
||||
ss << "Virtual Total: " << this->RamVirtualTotal << std::endl;
|
||||
ss << "Virtual Available: " << this->RamVirtualAvailable << std::endl;
|
||||
ss << "Virtual Used: " << this->RamVirtualUsed << std::endl;
|
||||
ss << "Virtual UsedByCurrentProcess: " << this->RamVirtualUsedByCurrentProcess << std::endl;
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
celero::RAMReport celero::RAMReport::operator-(const RAMReport& x)
|
||||
{
|
||||
celero::RAMReport r;
|
||||
r.RamSystemTotal = this->RamSystemTotal - x.RamSystemTotal;
|
||||
r.RamSystemAvailable = this->RamSystemAvailable - x.RamSystemAvailable;
|
||||
r.RamSystemUsed = this->RamSystemUsed - x.RamSystemUsed;
|
||||
r.RamSystemUsedByCurrentProcess = this->RamSystemUsedByCurrentProcess - x.RamSystemUsedByCurrentProcess;
|
||||
r.RamPhysicalTotal = this->RamPhysicalTotal - x.RamPhysicalTotal;
|
||||
r.RamPhysicalAvailable = this->RamPhysicalAvailable - x.RamPhysicalAvailable;
|
||||
r.RamPhysicalUsed = this->RamPhysicalUsed - x.RamPhysicalUsed;
|
||||
r.RamPhysicalUsedByCurrentProcess = this->RamPhysicalUsedByCurrentProcess - x.RamPhysicalUsedByCurrentProcess;
|
||||
r.RamPhysicalUsedByCurrentProcessPeak = this->RamPhysicalUsedByCurrentProcessPeak - x.RamPhysicalUsedByCurrentProcessPeak;
|
||||
r.RamVirtualTotal = this->RamVirtualTotal - x.RamVirtualTotal;
|
||||
r.RamVirtualAvailable = this->RamVirtualAvailable - x.RamVirtualAvailable;
|
||||
r.RamVirtualUsed = this->RamVirtualUsed - x.RamVirtualUsed;
|
||||
r.RamVirtualUsedByCurrentProcess = this->RamVirtualUsedByCurrentProcess - x.RamVirtualUsedByCurrentProcess;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int64_t celero::GetRAMSystemTotal()
|
||||
{
|
||||
#ifdef WIN32
|
||||
MEMORYSTATUSEX memInfo;
|
||||
memInfo.dwLength = sizeof(MEMORYSTATUSEX);
|
||||
GlobalMemoryStatusEx(&memInfo);
|
||||
return static_cast<int64_t>(memInfo.ullTotalPhys) + static_cast<int64_t>(memInfo.ullTotalVirtual);
|
||||
#elif defined(__unix__) || defined(__unix) || defined(unix)
|
||||
// Prefer sysctl() over sysconf() except sysctl() HW_REALMEM and HW_PHYSMEM
|
||||
// return static_cast<int64_t>(sysconf(_SC_PHYS_PAGES)) * static_cast<int64_t>(sysconf(_SC_PAGE_SIZE));
|
||||
struct sysinfo memInfo;
|
||||
sysinfo(&memInfo);
|
||||
int64_t total = memInfo.totalram;
|
||||
total += memInfo.totalswap;
|
||||
total += memInfo.totalhigh;
|
||||
return total * static_cast<int64_t>(memInfo.mem_unit);
|
||||
#elif defined(__APPLE__)
|
||||
int mib[2];
|
||||
mib[0] = CTL_HW;
|
||||
mib[1] = HW_MEMSIZE;
|
||||
|
||||
int64_t memInfo{0};
|
||||
auto len = sizeof(memInfo);
|
||||
|
||||
if(sysctl(mib, 2, &memInfo, &len, nullptr, 0) == 0)
|
||||
{
|
||||
return memInfo;
|
||||
}
|
||||
|
||||
return -1;
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
int64_t celero::GetRAMSystemAvailable()
|
||||
{
|
||||
#ifdef WIN32
|
||||
MEMORYSTATUSEX memInfo;
|
||||
memInfo.dwLength = sizeof(MEMORYSTATUSEX);
|
||||
GlobalMemoryStatusEx(&memInfo);
|
||||
return static_cast<int64_t>(memInfo.ullAvailPhys) + static_cast<int64_t>(memInfo.ullAvailVirtual);
|
||||
#else
|
||||
return celero::GetRAMSystemTotal() - celero::GetRAMSystemUsed();
|
||||
#endif
|
||||
}
|
||||
|
||||
int64_t celero::GetRAMSystemUsed()
|
||||
{
|
||||
#ifdef WIN32
|
||||
return celero::GetRAMSystemTotal() - celero::GetRAMSystemAvailable();
|
||||
#elif defined(__APPLE__)
|
||||
int mib[2];
|
||||
mib[0] = CTL_HW;
|
||||
mib[1] = HW_MEMSIZE;
|
||||
|
||||
std::array<int64_t, 2> memInfo{{0, 0}};
|
||||
auto len = sizeof(memInfo[0]);
|
||||
|
||||
if(sysctl(mib, 2, &memInfo[0], &len, nullptr, 0) == 0)
|
||||
{
|
||||
if(sysctl(mib, 2, &memInfo[1], &len, nullptr, 0) == 0)
|
||||
{
|
||||
return memInfo[0] + memInfo[1];
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
#else
|
||||
struct sysinfo memInfo;
|
||||
sysinfo(&memInfo);
|
||||
int64_t total = memInfo.totalram - memInfo.freeram;
|
||||
total += memInfo.totalswap - memInfo.freeswap;
|
||||
total += memInfo.totalhigh - memInfo.freehigh;
|
||||
return total * static_cast<int64_t>(memInfo.mem_unit);
|
||||
#endif
|
||||
}
|
||||
|
||||
int64_t celero::GetRAMSystemUsedByCurrentProcess()
|
||||
{
|
||||
#ifdef WIN32
|
||||
PROCESS_MEMORY_COUNTERS_EX pmc;
|
||||
GetProcessMemoryInfo(GetCurrentProcess(), reinterpret_cast<PPROCESS_MEMORY_COUNTERS>(&pmc), sizeof(pmc));
|
||||
return static_cast<int64_t>(pmc.WorkingSetSize);
|
||||
#else
|
||||
return celero::GetRAMPhysicalUsedByCurrentProcess() + celero::GetRAMVirtualUsedByCurrentProcess();
|
||||
#endif
|
||||
}
|
||||
|
||||
int64_t celero::GetRAMPhysicalTotal()
|
||||
{
|
||||
#ifdef WIN32
|
||||
MEMORYSTATUSEX memInfo;
|
||||
memInfo.dwLength = sizeof(MEMORYSTATUSEX);
|
||||
GlobalMemoryStatusEx(&memInfo);
|
||||
return static_cast<int64_t>(memInfo.ullTotalPhys);
|
||||
#elif defined(__APPLE__)
|
||||
return -1;
|
||||
#else
|
||||
struct sysinfo memInfo;
|
||||
sysinfo(&memInfo);
|
||||
return memInfo.totalram * memInfo.mem_unit;
|
||||
#endif
|
||||
}
|
||||
|
||||
int64_t celero::GetRAMPhysicalAvailable()
|
||||
{
|
||||
#ifdef WIN32
|
||||
MEMORYSTATUSEX memInfo;
|
||||
memInfo.dwLength = sizeof(MEMORYSTATUSEX);
|
||||
GlobalMemoryStatusEx(&memInfo);
|
||||
return static_cast<int64_t>(memInfo.ullAvailPhys);
|
||||
#else
|
||||
return celero::GetRAMPhysicalTotal() - celero::GetRAMPhysicalUsed();
|
||||
#endif
|
||||
}
|
||||
|
||||
int64_t celero::GetRAMPhysicalUsed()
|
||||
{
|
||||
#ifdef WIN32
|
||||
return celero::GetRAMPhysicalTotal() - celero::GetRAMPhysicalAvailable();
|
||||
#elif defined(__APPLE__)
|
||||
struct rusage rusage;
|
||||
getrusage(RUSAGE_SELF, &rusage);
|
||||
return (size_t)rusage.ru_maxrss;
|
||||
#else
|
||||
struct sysinfo memInfo;
|
||||
sysinfo(&memInfo);
|
||||
return (static_cast<int64_t>(memInfo.totalram) - static_cast<int64_t>(memInfo.freeram)) * static_cast<int64_t>(memInfo.mem_unit);
|
||||
#endif
|
||||
}
|
||||
|
||||
int64_t celero::GetRAMPhysicalUsedByCurrentProcess()
|
||||
{
|
||||
#ifdef WIN32
|
||||
PROCESS_MEMORY_COUNTERS_EX pmc;
|
||||
GetProcessMemoryInfo(GetCurrentProcess(), reinterpret_cast<PPROCESS_MEMORY_COUNTERS>(&pmc), sizeof(pmc));
|
||||
return static_cast<int64_t>(pmc.WorkingSetSize);
|
||||
#else
|
||||
constexpr int BufferSize{128};
|
||||
int64_t result = 0;
|
||||
auto file = fopen("/proc/self/status", "r");
|
||||
char line[BufferSize];
|
||||
|
||||
while(fgets(line, BufferSize, file) != nullptr)
|
||||
{
|
||||
if(strncmp(line, "VmRSS:", 6) == 0)
|
||||
{
|
||||
result += celero::impl::ParseLine(line) * Kilobytes2Bytes;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
return static_cast<int64_t>(result);
|
||||
#endif
|
||||
}
|
||||
|
||||
int64_t celero::GetRAMPhysicalUsedByCurrentProcessPeak()
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
PROCESS_MEMORY_COUNTERS pmc;
|
||||
GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc));
|
||||
return static_cast<int64_t>(pmc.PeakWorkingSetSize);
|
||||
#elif defined(__APPLE__) && defined(__MACH__)
|
||||
struct rusage rusage;
|
||||
getrusage(RUSAGE_SELF, &rusage);
|
||||
return static_cast<int64_t>(rusage.ru_maxrss);
|
||||
#else
|
||||
constexpr int BufferSize{128};
|
||||
int64_t result = 0;
|
||||
auto file = fopen("/proc/self/status", "r");
|
||||
char line[BufferSize];
|
||||
|
||||
while(fgets(line, BufferSize, file) != nullptr)
|
||||
{
|
||||
if(strncmp(line, "VmHWM:", 6) == 0)
|
||||
{
|
||||
result += celero::impl::ParseLine(line) * Kilobytes2Bytes;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
return static_cast<int64_t>(result);
|
||||
#endif
|
||||
}
|
||||
|
||||
int64_t celero::GetRAMVirtualTotal()
|
||||
{
|
||||
#ifdef WIN32
|
||||
MEMORYSTATUSEX memInfo;
|
||||
memInfo.dwLength = sizeof(MEMORYSTATUSEX);
|
||||
GlobalMemoryStatusEx(&memInfo);
|
||||
return memInfo.ullTotalPageFile;
|
||||
#elif defined(__APPLE__)
|
||||
return -1;
|
||||
#else
|
||||
struct sysinfo memInfo;
|
||||
sysinfo(&memInfo);
|
||||
return static_cast<int64_t>(memInfo.totalswap) * static_cast<int64_t>(memInfo.mem_unit);
|
||||
#endif
|
||||
}
|
||||
|
||||
int64_t celero::GetRAMVirtualAvailable()
|
||||
{
|
||||
#ifdef WIN32
|
||||
MEMORYSTATUSEX memInfo;
|
||||
memInfo.dwLength = sizeof(MEMORYSTATUSEX);
|
||||
GlobalMemoryStatusEx(&memInfo);
|
||||
return memInfo.ullTotalPageFile;
|
||||
#else
|
||||
return celero::GetRAMVirtualTotal() - celero::GetRAMVirtualUsed();
|
||||
#endif
|
||||
}
|
||||
|
||||
int64_t celero::GetRAMVirtualUsed()
|
||||
{
|
||||
#ifdef WIN32
|
||||
return celero::GetRAMVirtualTotal() - celero::GetRAMVirtualAvailable();
|
||||
#elif defined(__APPLE__)
|
||||
return -1;
|
||||
#else
|
||||
struct sysinfo memInfo;
|
||||
sysinfo(&memInfo);
|
||||
const int64_t total = memInfo.totalswap - memInfo.freeswap;
|
||||
return total * static_cast<int64_t>(memInfo.mem_unit);
|
||||
#endif
|
||||
}
|
||||
|
||||
int64_t celero::GetRAMVirtualUsedByCurrentProcess()
|
||||
{
|
||||
#ifdef WIN32
|
||||
PROCESS_MEMORY_COUNTERS_EX pmc;
|
||||
GetProcessMemoryInfo(GetCurrentProcess(), reinterpret_cast<PPROCESS_MEMORY_COUNTERS>(&pmc), sizeof(pmc));
|
||||
return pmc.PrivateUsage;
|
||||
#else
|
||||
// Verified Correct.
|
||||
constexpr int BufferSize{128};
|
||||
int64_t result = 0;
|
||||
FILE* file = fopen("/proc/self/status", "r");
|
||||
char line[BufferSize];
|
||||
|
||||
while(fgets(line, BufferSize, file) != NULL)
|
||||
{
|
||||
if(strncmp(line, "VmSize:", 7) == 0)
|
||||
{
|
||||
result = celero::impl::ParseLine(line) * Kilobytes2Bytes;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
celero::RAMReport celero::GetRAMReport()
|
||||
{
|
||||
celero::RAMReport r;
|
||||
r.RamSystemTotal = GetRAMSystemTotal();
|
||||
r.RamSystemAvailable = GetRAMSystemAvailable();
|
||||
r.RamSystemUsed = GetRAMSystemUsed();
|
||||
r.RamSystemUsedByCurrentProcess = GetRAMSystemUsedByCurrentProcess();
|
||||
r.RamPhysicalTotal = GetRAMPhysicalTotal();
|
||||
r.RamPhysicalAvailable = GetRAMPhysicalAvailable();
|
||||
r.RamPhysicalUsed = GetRAMPhysicalUsed();
|
||||
r.RamPhysicalUsedByCurrentProcess = GetRAMPhysicalUsedByCurrentProcess();
|
||||
r.RamVirtualTotal = GetRAMVirtualTotal();
|
||||
r.RamVirtualAvailable = GetRAMVirtualAvailable();
|
||||
r.RamVirtualUsed = GetRAMVirtualUsed();
|
||||
r.RamVirtualUsedByCurrentProcess = GetRAMVirtualUsedByCurrentProcess();
|
||||
return r;
|
||||
}
|
142
celero/celero/Memory.h
Normal file
142
celero/celero/Memory.h
Normal file
@ -0,0 +1,142 @@
|
||||
#ifndef H_CELERO_MEORY_H
|
||||
#define H_CELERO_MEORY_H
|
||||
|
||||
///
|
||||
/// \author John Farrier
|
||||
///
|
||||
/// \copyright Copyright 2018 John Farrier
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
|
||||
#include <celero/Export.h>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
namespace celero
|
||||
{
|
||||
///
|
||||
/// \struct RAMReport
|
||||
///
|
||||
/// Contans all Memory measurements (in bytes)
|
||||
///
|
||||
struct RAMReport
|
||||
{
|
||||
int64_t RamSystemTotal{0};
|
||||
int64_t RamSystemAvailable{0};
|
||||
int64_t RamSystemUsed{0};
|
||||
int64_t RamSystemUsedByCurrentProcess{0};
|
||||
int64_t RamPhysicalTotal{0};
|
||||
int64_t RamPhysicalAvailable{0};
|
||||
int64_t RamPhysicalUsed{0};
|
||||
int64_t RamPhysicalUsedByCurrentProcess{0};
|
||||
int64_t RamPhysicalUsedByCurrentProcessPeak{0};
|
||||
int64_t RamVirtualTotal{0};
|
||||
int64_t RamVirtualAvailable{0};
|
||||
int64_t RamVirtualUsed{0};
|
||||
int64_t RamVirtualUsedByCurrentProcess{0};
|
||||
|
||||
operator std::string();
|
||||
celero::RAMReport operator-(const celero::RAMReport& x);
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// Physical + Virtual Memory
|
||||
|
||||
CELERO_EXPORT int64_t GetRAMSystemTotal();
|
||||
CELERO_EXPORT int64_t GetRAMSystemAvailable();
|
||||
CELERO_EXPORT int64_t GetRAMSystemUsed();
|
||||
|
||||
///
|
||||
/// The sum of the physical RAM used by the current process and the virtual RAM used by the current process.
|
||||
///
|
||||
CELERO_EXPORT int64_t GetRAMSystemUsedByCurrentProcess();
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// Physical Memory
|
||||
|
||||
///
|
||||
/// The total physical RAM, in bytes.
|
||||
/// https://msdn.microsoft.com/en-us/library/windows/desktop/aa366770(v=vs.85).aspx
|
||||
///
|
||||
CELERO_EXPORT int64_t GetRAMPhysicalTotal();
|
||||
|
||||
///
|
||||
/// The total physical RAM available to the current process, in bytes.
|
||||
///
|
||||
/// On Windows, this is defined as "This is the amount of physical memory that can be immediately reused without having to write its contents to
|
||||
/// disk first. It is the sum of the size of the standby, free, and zero lists."
|
||||
/// https://msdn.microsoft.com/en-us/library/windows/desktop/aa366770(v=vs.85).aspx
|
||||
///
|
||||
CELERO_EXPORT int64_t GetRAMPhysicalAvailable();
|
||||
|
||||
///
|
||||
/// The total amount of physical RAM minus the amount of physical RAM which is available.
|
||||
///
|
||||
CELERO_EXPORT int64_t GetRAMPhysicalUsed();
|
||||
|
||||
///
|
||||
/// On Windows, this is defined by the Working Set Size. The working set size is defined as "The working set of a process is the set of pages in
|
||||
/// the virtual address space of the process that are currently resident in physical memory. The working set contains only pageable memory
|
||||
/// allocations; nonpageable memory allocations such as Address Windowing Extensions (AWE) or large page allocations are not included in the
|
||||
/// working set."
|
||||
/// https://msdn.microsoft.com/en-us/library/windows/desktop/ms684877(v=vs.85).aspx
|
||||
/// https://msdn.microsoft.com/en-us/library/windows/desktop/cc441804(v=vs.85).aspx
|
||||
///
|
||||
CELERO_EXPORT int64_t GetRAMPhysicalUsedByCurrentProcess();
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
CELERO_EXPORT int64_t GetRAMPhysicalUsedByCurrentProcessPeak();
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// Virtual Memory
|
||||
|
||||
///
|
||||
/// The total amount of Virtual RAM (page file size).
|
||||
///
|
||||
/// On Windows, this is defined by the amount of page file that the current process has access to. It is not the total available on the system.
|
||||
/// From the Windows documentation: "The current committed memory limit for the system or the current process, whichever is smaller, in bytes. To
|
||||
/// get the system-wide committed memory limit, call GetPerformanceInfo."
|
||||
///
|
||||
CELERO_EXPORT int64_t GetRAMVirtualTotal();
|
||||
|
||||
///
|
||||
/// The amount of non-physical memory (page file) available.
|
||||
///
|
||||
/// On Windows, this is defined by the amount of page file that the current process has access to. It is not the total available on the system.
|
||||
/// From the Windows documentation: "The maximum amount of memory the current process can commit, in bytes. This value is equal to or smaller than
|
||||
/// the system-wide available commit value."
|
||||
///
|
||||
CELERO_EXPORT int64_t GetRAMVirtualAvailable();
|
||||
|
||||
///
|
||||
/// The total virtual RAM minus the available virtual RAM.
|
||||
///
|
||||
CELERO_EXPORT int64_t GetRAMVirtualUsed();
|
||||
|
||||
///
|
||||
/// On Windows, this is defined as the commit charge. "The Commit Charge value in bytes for this process. Commit Charge is the total amount of
|
||||
/// memory that the memory manager has committed for a running process."
|
||||
/// https://msdn.microsoft.com/en-us/library/windows/desktop/ms684877(v=vs.85).aspx
|
||||
///
|
||||
CELERO_EXPORT int64_t GetRAMVirtualUsedByCurrentProcess();
|
||||
|
||||
///
|
||||
/// Returns a RAMReport class containing all RAM measurements.
|
||||
///
|
||||
CELERO_EXPORT celero::RAMReport GetRAMReport();
|
||||
} // namespace celero
|
||||
|
||||
#endif
|
65
celero/celero/Pimpl.h
Normal file
65
celero/celero/Pimpl.h
Normal file
@ -0,0 +1,65 @@
|
||||
#ifndef H_CELERO_PIMPL_H
|
||||
#define H_CELERO_PIMPL_H
|
||||
|
||||
///
|
||||
/// \author John Farrier
|
||||
///
|
||||
/// \copyright Copyright 2015, 2016, 2017, 2018 John Farrier
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
|
||||
#include <celero/Export.h>
|
||||
#include <memory>
|
||||
|
||||
namespace celero
|
||||
{
|
||||
///
|
||||
/// \class Pimpl
|
||||
///
|
||||
/// \author Herb Sutter
|
||||
/// \author John Farrier
|
||||
///
|
||||
/// Classes using this must overload the assignment operator.
|
||||
/// Original code by Herb Sutter. Adapted for more primitive compilers by John Farrier.
|
||||
///
|
||||
template <typename T>
|
||||
class Pimpl
|
||||
{
|
||||
public:
|
||||
Pimpl();
|
||||
// template<typename ...Args> Pimpl( Args&& ... );
|
||||
template <typename Arg1>
|
||||
Pimpl(Arg1&&);
|
||||
template <typename Arg1, typename Arg2>
|
||||
Pimpl(Arg1&&, Arg2&&);
|
||||
template <typename Arg1, typename Arg2, typename Arg3>
|
||||
Pimpl(Arg1&&, Arg2&&, Arg3&&);
|
||||
template <typename Arg1, typename Arg2, typename Arg3, typename Arg4>
|
||||
Pimpl(Arg1&&, Arg2&&, Arg3&&, Arg4&&);
|
||||
template <typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5>
|
||||
Pimpl(Arg1&&, Arg2&&, Arg3&&, Arg4&&, Arg5&&);
|
||||
template <typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5, typename Arg6>
|
||||
Pimpl(Arg1&&, Arg2&&, Arg3&&, Arg4&&, Arg5&&, Arg6&&);
|
||||
~Pimpl();
|
||||
|
||||
T* operator->();
|
||||
const T* operator->() const;
|
||||
T& operator*();
|
||||
|
||||
private:
|
||||
std::unique_ptr<T> _pimpl;
|
||||
};
|
||||
} // namespace celero
|
||||
|
||||
#endif
|
98
celero/celero/PimplImpl.h
Normal file
98
celero/celero/PimplImpl.h
Normal file
@ -0,0 +1,98 @@
|
||||
#ifndef H_CELERO_PIMPLIMPL_H
|
||||
#define H_CELERO_PIMPLIMPL_H
|
||||
|
||||
///
|
||||
/// \author John Farrier
|
||||
///
|
||||
/// \copyright Copyright 2015, 2016, 2017, 2018 John Farrier
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
namespace celero
|
||||
{
|
||||
template <typename T>
|
||||
Pimpl<T>::Pimpl() : _pimpl(new T())
|
||||
{
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <typename Arg1>
|
||||
Pimpl<T>::Pimpl(Arg1&& arg1) : _pimpl(new T(std::forward<Arg1>(arg1)))
|
||||
{
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <typename Arg1, typename Arg2>
|
||||
Pimpl<T>::Pimpl(Arg1&& arg1, Arg2&& arg2) : _pimpl(new T(std::forward<Arg1>(arg1), std::forward<Arg2>(arg2)))
|
||||
{
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <typename Arg1, typename Arg2, typename Arg3>
|
||||
Pimpl<T>::Pimpl(Arg1&& arg1, Arg2&& arg2, Arg3&& arg3)
|
||||
: _pimpl(new T(std::forward<Arg1>(arg1), std::forward<Arg2>(arg2), std::forward<Arg3>(arg3)))
|
||||
{
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <typename Arg1, typename Arg2, typename Arg3, typename Arg4>
|
||||
Pimpl<T>::Pimpl(Arg1&& arg1, Arg2&& arg2, Arg3&& arg3, Arg4&& arg4)
|
||||
: _pimpl(new T(std::forward<Arg1>(arg1), std::forward<Arg2>(arg2), std::forward<Arg3>(arg3), std::forward<Arg4>(arg4)))
|
||||
{
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5>
|
||||
Pimpl<T>::Pimpl(Arg1&& arg1, Arg2&& arg2, Arg3&& arg3, Arg4&& arg4, Arg5&& arg5)
|
||||
: _pimpl(
|
||||
new T(std::forward<Arg1>(arg1), std::forward<Arg2>(arg2), std::forward<Arg3>(arg3), std::forward<Arg4>(arg4), std::forward<Arg5>(arg5)))
|
||||
{
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5, typename Arg6>
|
||||
Pimpl<T>::Pimpl(Arg1&& arg1, Arg2&& arg2, Arg3&& arg3, Arg4&& arg4, Arg5&& arg5, Arg6&& arg6)
|
||||
: _pimpl(new T(std::forward<Arg1>(arg1), std::forward<Arg2>(arg2), std::forward<Arg3>(arg3), std::forward<Arg4>(arg4),
|
||||
std::forward<Arg5>(arg5), std::forward<Arg6>(arg6)))
|
||||
{
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
Pimpl<T>::~Pimpl()
|
||||
{
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T* Pimpl<T>::operator->()
|
||||
{
|
||||
return _pimpl.get();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
const T* Pimpl<T>::operator->() const
|
||||
{
|
||||
return _pimpl.get();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T& Pimpl<T>::operator*()
|
||||
{
|
||||
return *_pimpl.get();
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
324
celero/celero/Print.cpp
Normal file
324
celero/celero/Print.cpp
Normal file
@ -0,0 +1,324 @@
|
||||
///
|
||||
/// \author John Farrier
|
||||
///
|
||||
/// \copyright Copyright 2015, 2016, 2017, 2018 John Farrier
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
|
||||
#include <celero/Benchmark.h>
|
||||
#include <celero/Console.h>
|
||||
#include <celero/Print.h>
|
||||
#include <celero/TestVector.h>
|
||||
#include <celero/Timer.h>
|
||||
#include <celero/UserDefinedMeasurementCollector.h>
|
||||
#include <celero/Utilities.h>
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <unordered_map>
|
||||
|
||||
using namespace celero;
|
||||
|
||||
enum PrintConstants : size_t
|
||||
{
|
||||
ColumnSeperatorWidth = 3,
|
||||
DoubleDecimals = 5,
|
||||
NumberOfColumns = 8,
|
||||
ColumnWidth = 15
|
||||
};
|
||||
|
||||
///
|
||||
/// http://stackoverflow.com/questions/14765155/how-can-i-easily-format-my-data-table-in-c
|
||||
/// Center-aligns string within a field of width w. Pads with blank spaces to enforce alignment.
|
||||
///
|
||||
std::string PrintCenter(const std::string s, const size_t w = PrintConstants::ColumnWidth)
|
||||
{
|
||||
std::stringstream ss;
|
||||
std::stringstream spaces;
|
||||
|
||||
// count excess room to pad
|
||||
auto padding = w - s.size();
|
||||
|
||||
for(size_t i = 0; i < padding / 2; ++i)
|
||||
{
|
||||
spaces << " ";
|
||||
}
|
||||
|
||||
// format with padding
|
||||
ss << spaces.str() << s << spaces.str();
|
||||
|
||||
// if odd #, add 1 space
|
||||
if((padding > 0) && (padding % 2 != 0))
|
||||
{
|
||||
ss << " ";
|
||||
}
|
||||
|
||||
ss << " | ";
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
///
|
||||
/// http://stackoverflow.com/questions/14765155/how-can-i-easily-format-my-data-table-in-c
|
||||
/// Convert double to string with specified number of places after the decimal and left padding.
|
||||
///
|
||||
std::string PrintColumn(const double x, const size_t decDigits = PrintConstants::DoubleDecimals, const size_t width = PrintConstants::ColumnWidth)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << std::fixed << std::right;
|
||||
|
||||
// fill space around displayed #
|
||||
ss.fill(' ');
|
||||
|
||||
// set width around displayed #
|
||||
ss.width(width);
|
||||
|
||||
// set # places after decimal
|
||||
ss.precision(decDigits);
|
||||
ss << x << " | ";
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
///
|
||||
/// http://stackoverflow.com/questions/14765155/how-can-i-easily-format-my-data-table-in-c
|
||||
/// Convert double to string with specified number of places after the decimal.
|
||||
///
|
||||
std::string PrintColumn(const int64_t x, const size_t width = PrintConstants::ColumnWidth)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << std::fixed;
|
||||
|
||||
// fill space around displayed #
|
||||
ss.fill(' ');
|
||||
|
||||
// set width around displayed #
|
||||
ss.width(width);
|
||||
|
||||
ss << x << " | ";
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
///
|
||||
/// http://stackoverflow.com/questions/14765155/how-can-i-easily-format-my-data-table-in-c
|
||||
/// Convert double to string with specified number of places after the decimal.
|
||||
///
|
||||
std::string PrintColumn(const uint64_t x, const size_t width = PrintConstants::ColumnWidth)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << std::fixed;
|
||||
|
||||
// fill space around displayed #
|
||||
ss.fill(' ');
|
||||
|
||||
// set width around displayed #
|
||||
ss.width(width);
|
||||
|
||||
ss << x << " | ";
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
///
|
||||
/// http://stackoverflow.com/questions/14765155/how-can-i-easily-format-my-data-table-in-c
|
||||
/// Convert double to string with specified number of places after the decimal.
|
||||
///
|
||||
std::string PrintStrColumnAligned(const std::string& x, const size_t width = PrintConstants::ColumnWidth, bool alignLeft = true)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << std::fixed << (alignLeft ? std::left : std::right);
|
||||
|
||||
// fill space around displayed #
|
||||
ss.fill(' ');
|
||||
|
||||
// set width around displayed #
|
||||
ss.width(width);
|
||||
|
||||
if(x.length() > width)
|
||||
{
|
||||
// Truncate
|
||||
std::string xTrunc = x;
|
||||
xTrunc = xTrunc.substr(0, width);
|
||||
ss << xTrunc << " | ";
|
||||
}
|
||||
else
|
||||
{
|
||||
ss << x << " | ";
|
||||
}
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string PrintColumn(const std::string& x, const size_t width = PrintConstants::ColumnWidth)
|
||||
{
|
||||
return PrintStrColumnAligned(x, width);
|
||||
}
|
||||
|
||||
std::string PrintColumnRight(const std::string& x, const size_t width = PrintConstants::ColumnWidth)
|
||||
{
|
||||
return PrintStrColumnAligned(x, width, false);
|
||||
}
|
||||
|
||||
std::string PrintHRule(const size_t additionalColumns = 0)
|
||||
{
|
||||
std::stringstream ss;
|
||||
std::string column{":"};
|
||||
|
||||
while(column.length() < PrintConstants::ColumnWidth)
|
||||
{
|
||||
column += "-";
|
||||
}
|
||||
|
||||
std::string firstColumn = column + ":|";
|
||||
|
||||
column += "-:|";
|
||||
|
||||
ss << "|" << firstColumn;
|
||||
|
||||
for(size_t i = 0; i < PrintConstants::NumberOfColumns + additionalColumns - 1; ++i)
|
||||
{
|
||||
ss << column;
|
||||
}
|
||||
|
||||
ss << std::endl;
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
namespace celero
|
||||
{
|
||||
void Printer::Console(const std::string& x)
|
||||
{
|
||||
std::cout << "Celero: " << x << std::endl;
|
||||
}
|
||||
|
||||
void Printer::TableBanner()
|
||||
{
|
||||
celero::console::SetConsoleColor(celero::console::ConsoleColor_Default);
|
||||
|
||||
std::cout << "|" << PrintCenter("Group") << PrintCenter("Experiment") << PrintCenter("Prob. Space") << PrintCenter("Samples")
|
||||
<< PrintCenter("Iterations") << PrintCenter("Baseline") << PrintCenter("us/Iteration") << PrintCenter("Iterations/sec");
|
||||
|
||||
for(size_t i = PrintConstants::NumberOfColumns; i < this->columnWidths.size(); ++i)
|
||||
{
|
||||
std::cout << PrintCenter(this->userDefinedColumns[i - PrintConstants::NumberOfColumns], this->columnWidths[i]);
|
||||
}
|
||||
|
||||
std::cout << "\n";
|
||||
std::cout << PrintHRule(this->userDefinedColumns.size());
|
||||
}
|
||||
|
||||
void Printer::TableRowExperimentHeader(Experiment* x)
|
||||
{
|
||||
celero::console::SetConsoleColor(celero::console::ConsoleColor_Default);
|
||||
std::cout << "|" << PrintColumn(x->getBenchmark()->getName()) << PrintColumn(x->getName());
|
||||
}
|
||||
|
||||
void Printer::TableRowFailure(const std::string& msg)
|
||||
{
|
||||
std::cout << PrintColumnRight("-") << PrintColumnRight("-") << PrintColumnRight("-");
|
||||
|
||||
for(size_t i = PrintConstants::NumberOfColumns; i < this->columnWidths.size(); ++i)
|
||||
{
|
||||
std::cout << PrintColumnRight("-", this->columnWidths[i]);
|
||||
}
|
||||
|
||||
celero::console::SetConsoleColor(celero::console::ConsoleColor_Red);
|
||||
std::cout << msg << std::endl;
|
||||
celero::console::SetConsoleColor(celero::console::ConsoleColor_Default);
|
||||
}
|
||||
|
||||
void Printer::TableRowProblemSpaceHeader(std::shared_ptr<celero::ExperimentResult> x)
|
||||
{
|
||||
celero::console::SetConsoleColor(celero::console::ConsoleColor_Default);
|
||||
|
||||
if(x->getProblemSpaceValue() == static_cast<int64_t>(TestFixture::Constants::NoProblemSpaceValue))
|
||||
{
|
||||
std::cout << PrintColumnRight("Null");
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << PrintColumn(x->getProblemSpaceValue());
|
||||
}
|
||||
|
||||
std::cout << PrintColumn(x->getExperiment()->getSamples()) << PrintColumn(x->getProblemSpaceIterations());
|
||||
}
|
||||
|
||||
void Printer::TableRowHeader(std::shared_ptr<celero::ExperimentResult> x)
|
||||
{
|
||||
TableRowExperimentHeader(x->getExperiment());
|
||||
TableRowProblemSpaceHeader(x);
|
||||
}
|
||||
|
||||
void Printer::TableResult(std::shared_ptr<celero::ExperimentResult> x)
|
||||
{
|
||||
celero::console::SetConsoleColor(celero::console::ConsoleColor_Default);
|
||||
|
||||
// Slower than Baseline
|
||||
if(x->getBaselineMeasurement() > 1.0)
|
||||
{
|
||||
celero::console::SetConsoleColor(celero::console::ConsoleColor_Yellow);
|
||||
}
|
||||
else if(x->getBaselineMeasurement() < 1.0)
|
||||
{
|
||||
celero::console::SetConsoleColor(celero::console::ConsoleColor_Green);
|
||||
}
|
||||
else
|
||||
{
|
||||
celero::console::SetConsoleColor(celero::console::ConsoleColor_Cyan);
|
||||
}
|
||||
|
||||
std::cout << PrintColumn(x->getBaselineMeasurement()) << PrintColumn(x->getUsPerCall()) << PrintColumn(x->getCallsPerSecond(), 2);
|
||||
|
||||
celero::console::SetConsoleColor(celero::console::ConsoleColor_Default);
|
||||
|
||||
std::unordered_map<std::string, double> udmValues;
|
||||
|
||||
auto udmCollector = x->getUserDefinedMeasurements();
|
||||
for(const auto& entry : udmCollector->getAggregateValues())
|
||||
{
|
||||
udmValues[entry.first] = entry.second;
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < this->userDefinedColumns.size(); ++i)
|
||||
{
|
||||
const auto& fieldName = this->userDefinedColumns[i];
|
||||
|
||||
if(udmValues.find(fieldName) == udmValues.end())
|
||||
{
|
||||
std::cout << PrintCenter("---", this->columnWidths[i + PrintConstants::NumberOfColumns]);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << PrintColumn(udmValues.at(fieldName), 2, this->columnWidths[i + PrintConstants::NumberOfColumns]);
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "\n";
|
||||
}
|
||||
|
||||
void Printer::initialize(std::vector<std::string> userDefinedColumnsIn)
|
||||
{
|
||||
this->userDefinedColumns = userDefinedColumnsIn;
|
||||
|
||||
this->columnWidths.clear();
|
||||
this->columnWidths.resize(PrintConstants::NumberOfColumns, PrintConstants::ColumnWidth);
|
||||
|
||||
for(const auto& name : this->userDefinedColumns)
|
||||
{
|
||||
this->columnWidths.push_back(std::max(name.size() + 2, (size_t)PrintConstants::ColumnWidth));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace celero
|
65
celero/celero/Print.h
Normal file
65
celero/celero/Print.h
Normal file
@ -0,0 +1,65 @@
|
||||
#ifndef H_CELERO_PRINT_H
|
||||
#define H_CELERO_PRINT_H
|
||||
|
||||
///
|
||||
/// \author John Farrier
|
||||
///
|
||||
/// \copyright Copyright 2015, 2016, 2017, 2018 John Farrier
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
|
||||
#include <celero/Experiment.h>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace celero
|
||||
{
|
||||
///
|
||||
/// \class Printer
|
||||
///
|
||||
/// \author John farrier
|
||||
///
|
||||
class Printer
|
||||
{
|
||||
public:
|
||||
///
|
||||
/// Singleton implementation.
|
||||
static Printer& get()
|
||||
{
|
||||
static Printer p;
|
||||
return p;
|
||||
}
|
||||
|
||||
///
|
||||
/// Initialize the Printer object with specific user-defined columns.
|
||||
///
|
||||
void initialize(std::vector<std::string> userDefinedColumns);
|
||||
|
||||
void Console(const std::string& x);
|
||||
void TableBanner();
|
||||
void TableRowExperimentHeader(Experiment* x);
|
||||
void TableRowFailure(const std::string& msg);
|
||||
void TableRowProblemSpaceHeader(std::shared_ptr<celero::ExperimentResult> x);
|
||||
void TableRowHeader(std::shared_ptr<celero::ExperimentResult> x);
|
||||
void TableResult(std::shared_ptr<celero::ExperimentResult> x);
|
||||
|
||||
private:
|
||||
Printer() = default;
|
||||
|
||||
std::vector<std::string> userDefinedColumns;
|
||||
std::vector<size_t> columnWidths;
|
||||
};
|
||||
} // namespace celero
|
||||
|
||||
#endif
|
125
celero/celero/ResultTable.cpp
Normal file
125
celero/celero/ResultTable.cpp
Normal file
@ -0,0 +1,125 @@
|
||||
///
|
||||
/// \author John Farrier
|
||||
///
|
||||
/// \copyright Copyright 2015, 2016, 2017, 2018 John Farrier
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
|
||||
#include <celero/Benchmark.h>
|
||||
#include <celero/PimplImpl.h>
|
||||
#include <celero/ResultTable.h>
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
using namespace celero;
|
||||
|
||||
///
|
||||
/// \class Impl
|
||||
///
|
||||
class celero::ResultTable::Impl
|
||||
{
|
||||
public:
|
||||
Impl() : precision(5)
|
||||
{
|
||||
}
|
||||
|
||||
~Impl()
|
||||
{
|
||||
closeFile();
|
||||
}
|
||||
|
||||
void closeFile()
|
||||
{
|
||||
if(this->ofs.is_open() == true)
|
||||
{
|
||||
this->ofs.close();
|
||||
}
|
||||
}
|
||||
|
||||
void setFileName(const std::string& x)
|
||||
{
|
||||
if(this->ofs.is_open() == true)
|
||||
{
|
||||
this->ofs.close();
|
||||
}
|
||||
|
||||
this->ofs.open(x);
|
||||
|
||||
// Print the header for the table.
|
||||
if(this->ofs.is_open() == true)
|
||||
{
|
||||
this->ofs << "Group,Experiment,Problem "
|
||||
"Space,Samples,Iterations,Failure,Baseline,";
|
||||
this->ofs << "us/Iteration,Iterations/sec,Min (us),Mean (us),Max "
|
||||
"(us),Variance,Standard Deviation,Skewness,Kurtosis,Z Score"
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
std::string format(double x)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << std::fixed;
|
||||
ss.precision(this->precision);
|
||||
ss << x;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::ofstream ofs;
|
||||
const size_t precision;
|
||||
};
|
||||
|
||||
ResultTable::ResultTable() : pimpl()
|
||||
{
|
||||
}
|
||||
|
||||
ResultTable::~ResultTable()
|
||||
{
|
||||
}
|
||||
|
||||
ResultTable& ResultTable::Instance()
|
||||
{
|
||||
static ResultTable singleton;
|
||||
return singleton;
|
||||
}
|
||||
|
||||
void ResultTable::setFileName(const std::string& x)
|
||||
{
|
||||
assert(x.empty() == false);
|
||||
this->pimpl->setFileName(x);
|
||||
}
|
||||
|
||||
void ResultTable::closeFile()
|
||||
{
|
||||
this->pimpl->closeFile();
|
||||
}
|
||||
|
||||
void ResultTable::add(std::shared_ptr<celero::ExperimentResult> x)
|
||||
{
|
||||
if(this->pimpl->ofs.is_open() == true)
|
||||
{
|
||||
this->pimpl->ofs << x->getExperiment()->getBenchmark()->getName() << "," << x->getExperiment()->getName() << "," << x->getProblemSpaceValue()
|
||||
<< "," << x->getExperiment()->getSamples() << "," << x->getProblemSpaceIterations() << "," << x->getFailure() << ",";
|
||||
|
||||
this->pimpl->ofs << x->getBaselineMeasurement() << "," << x->getUsPerCall() << "," << x->getCallsPerSecond() << ","
|
||||
<< x->getTimeStatistics()->getMin() << "," << x->getTimeStatistics()->getMean() << "," << x->getTimeStatistics()->getMax()
|
||||
<< "," << x->getTimeStatistics()->getVariance() << "," << x->getTimeStatistics()->getStandardDeviation() << ","
|
||||
<< x->getTimeStatistics()->getSkewness() << "," << x->getTimeStatistics()->getKurtosis() << ","
|
||||
<< x->getTimeStatistics()->getZScore() << std::endl;
|
||||
}
|
||||
}
|
87
celero/celero/ResultTable.h
Normal file
87
celero/celero/ResultTable.h
Normal file
@ -0,0 +1,87 @@
|
||||
#ifndef H_CELERO_RESULTTABLE_H
|
||||
#define H_CELERO_RESULTTABLE_H
|
||||
|
||||
///
|
||||
/// \author John Farrier
|
||||
///
|
||||
/// \copyright Copyright 2015, 2016, 2017, 2018 John Farrier
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
|
||||
#include <celero/Experiment.h>
|
||||
#include <celero/Pimpl.h>
|
||||
#include <string>
|
||||
|
||||
namespace celero
|
||||
{
|
||||
///
|
||||
/// \class ResultTable
|
||||
///
|
||||
/// \author John Farrier
|
||||
///
|
||||
class ResultTable
|
||||
{
|
||||
public:
|
||||
///
|
||||
/// Singleton
|
||||
///
|
||||
static ResultTable& Instance();
|
||||
|
||||
///
|
||||
/// Specify a file name for a results output file.
|
||||
///
|
||||
/// \param x The name of the output file in which to store Celero's results.
|
||||
///
|
||||
void setFileName(const std::string& x);
|
||||
|
||||
///
|
||||
/// Force the output file (if any) to close
|
||||
///
|
||||
void closeFile();
|
||||
///
|
||||
/// Add a new result to the result table.
|
||||
///
|
||||
/// This should re-save on every new result so that the output can be monitored externally.
|
||||
///
|
||||
void add(std::shared_ptr<celero::ExperimentResult> x);
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
void save();
|
||||
|
||||
private:
|
||||
///
|
||||
/// Default Constructor
|
||||
///
|
||||
ResultTable();
|
||||
|
||||
///
|
||||
/// Default Destructor
|
||||
///
|
||||
~ResultTable();
|
||||
|
||||
///
|
||||
/// \brief Pimpl Idiom
|
||||
///
|
||||
class Impl;
|
||||
|
||||
///
|
||||
/// \brief Pimpl Idiom
|
||||
///
|
||||
Pimpl<Impl> pimpl;
|
||||
};
|
||||
} // namespace celero
|
||||
|
||||
#endif
|
252
celero/celero/Statistics.h
Normal file
252
celero/celero/Statistics.h
Normal file
@ -0,0 +1,252 @@
|
||||
#ifndef H_CELERO_STATISTICS_H
|
||||
#define H_CELERO_STATISTICS_H
|
||||
|
||||
///
|
||||
/// \author John Farrier
|
||||
///
|
||||
/// \copyright Copyright 2015, 2016, 2017, 2018 John Farrier
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
|
||||
namespace celero
|
||||
{
|
||||
///
|
||||
/// \class Statistics
|
||||
///
|
||||
/// \author John Farrier
|
||||
///
|
||||
/// Sources:
|
||||
/// http://www.johndcook.com/skewness_kurtosis.html
|
||||
/// http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
|
||||
/// http://prod.sandia.gov/techlib/access-control.cgi/2008/086212.pdf
|
||||
/// http://en.wikipedia.org/wiki/Kurtosis
|
||||
///
|
||||
template <typename T = int64_t>
|
||||
class Statistics
|
||||
{
|
||||
static_assert(std::is_arithmetic<T>::value, "Statistics requres an arithmetic type.");
|
||||
|
||||
public:
|
||||
///
|
||||
/// \brief Default constructor
|
||||
///
|
||||
Statistics() = default;
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Statistics(const Statistics& other) :
|
||||
sampleSize(other.sampleSize),
|
||||
M1(other.M1),
|
||||
M2(other.M2),
|
||||
M3(other.M3),
|
||||
M4(other.M4),
|
||||
min(other.min),
|
||||
max(other.max)
|
||||
{
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
~Statistics() = default;
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Statistics operator+(const Statistics<T>& other)
|
||||
{
|
||||
Statistics<T> combined;
|
||||
|
||||
combined.sampleSize = this->sampleSize + other.sampleSize;
|
||||
|
||||
const auto delta = other.M1 - this->M1;
|
||||
const auto delta2 = delta * delta;
|
||||
const auto delta3 = delta * delta2;
|
||||
const auto delta4 = delta2 * delta2;
|
||||
|
||||
combined.M1 = (this->sampleSize * this->M1 + other.sampleSize * other.M1) / combined.sampleSize;
|
||||
|
||||
combined.M2 = this->M2 + other.M2 + delta2 * this->sampleSize * other.sampleSize / combined.sampleSize;
|
||||
|
||||
combined.M3 =
|
||||
this->M3 + other.M3
|
||||
+ delta3 * this->sampleSize * other.sampleSize * (this->sampleSize - other.sampleSize) / (combined.sampleSize * combined.sampleSize);
|
||||
|
||||
combined.M3 += 3.0 * delta * (this->sampleSize * other.M2 - other.sampleSize * this->M2) / combined.sampleSize;
|
||||
|
||||
combined.M4 = this->M4 + other.M4
|
||||
+ delta4 * this->sampleSize * other.sampleSize
|
||||
* (this->sampleSize * this->sampleSize - this->sampleSize * other.sampleSize + other.sampleSize * other.sampleSize)
|
||||
/ (combined.sampleSize * combined.sampleSize * combined.sampleSize);
|
||||
|
||||
combined.M4 += 6.0 * delta2 * (this->sampleSize * this->sampleSize * other.M2 + other.sampleSize * other.sampleSize * this->M2)
|
||||
/ (combined.sampleSize * combined.sampleSize)
|
||||
+ 4.0 * delta * (this->sampleSize * other.M3 - other.sampleSize * this->M3) / combined.sampleSize;
|
||||
|
||||
combined.min = std::min(this->min, other.min);
|
||||
combined.max = std::max(this->max, other.max);
|
||||
|
||||
return combined;
|
||||
}
|
||||
|
||||
Statistics& operator+=(const Statistics& other)
|
||||
{
|
||||
const auto combined = *this + other;
|
||||
*this = combined;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Statistics& operator=(const Statistics& other)
|
||||
{
|
||||
this->sampleSize = other.sampleSize;
|
||||
this->M1 = other.M1;
|
||||
this->M2 = other.M2;
|
||||
this->M3 = other.M3;
|
||||
this->M4 = other.M4;
|
||||
this->min = other.min;
|
||||
this->max = other.max;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
///
|
||||
/// Resets all accumulated statistics.
|
||||
///
|
||||
void reset()
|
||||
{
|
||||
this->sampleSize = 0;
|
||||
this->M1 = 0;
|
||||
this->M2 = 0;
|
||||
this->M3 = 0;
|
||||
this->M4 = 0;
|
||||
this->min = std::numeric_limits<decltype(this->min)>::max();
|
||||
this->max = std::numeric_limits<decltype(this->max)>::min();
|
||||
}
|
||||
|
||||
///
|
||||
/// Adds a statistical sample.
|
||||
///
|
||||
void addSample(T x)
|
||||
{
|
||||
const auto n1 = this->sampleSize;
|
||||
this->sampleSize++;
|
||||
|
||||
const auto delta = x - this->M1;
|
||||
const auto delta_n = delta / this->sampleSize;
|
||||
const auto delta_n2 = delta_n * delta_n;
|
||||
const auto term1 = delta * delta_n * n1;
|
||||
|
||||
this->M1 += delta_n;
|
||||
this->M4 += term1 * delta_n2 * (this->sampleSize * this->sampleSize - 3 * this->sampleSize + 3) + 6 * delta_n2 * this->M2
|
||||
- 4 * delta_n * this->M3;
|
||||
this->M3 += term1 * delta_n * (this->sampleSize - 2) - 3 * delta_n * this->M2;
|
||||
this->M2 += term1;
|
||||
|
||||
this->min = std::min(this->min, x);
|
||||
this->max = std::max(this->max, x);
|
||||
}
|
||||
|
||||
size_t getSize() const
|
||||
{
|
||||
return this->sampleSize;
|
||||
}
|
||||
|
||||
double getMean() const
|
||||
{
|
||||
return this->M1;
|
||||
}
|
||||
|
||||
double getVariance() const
|
||||
{
|
||||
if(this->sampleSize > 1)
|
||||
{
|
||||
return this->M2 / (this->sampleSize - 1);
|
||||
}
|
||||
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
double getStandardDeviation() const
|
||||
{
|
||||
return std::sqrt(this->getVariance());
|
||||
}
|
||||
|
||||
double getSkewness() const
|
||||
{
|
||||
if(this->sampleSize > 2)
|
||||
{
|
||||
return sqrt(this->sampleSize) * this->M3 / pow(this->M2, 1.5);
|
||||
}
|
||||
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
double getKurtosis() const
|
||||
{
|
||||
if(this->sampleSize > 3)
|
||||
{
|
||||
if(this->M2 != 0)
|
||||
{
|
||||
return this->sampleSize * this->M4 / (this->M2 * this->M2) - 3.0;
|
||||
}
|
||||
}
|
||||
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
///
|
||||
/// Computed as (mean - hypothesis)/standard_deviation
|
||||
///
|
||||
/// Here, the hypothesis is our minimum value.
|
||||
///
|
||||
double getZScore() const
|
||||
{
|
||||
const auto sd = this->getStandardDeviation();
|
||||
|
||||
if(sd != 0.0)
|
||||
{
|
||||
return (this->getMean() - static_cast<double>(this->getMin())) / sd;
|
||||
}
|
||||
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
T getMin() const
|
||||
{
|
||||
return this->min;
|
||||
}
|
||||
|
||||
T getMax() const
|
||||
{
|
||||
return this->max;
|
||||
}
|
||||
|
||||
private:
|
||||
size_t sampleSize{0};
|
||||
double M1{0.0};
|
||||
double M2{0.0};
|
||||
double M3{0.0};
|
||||
double M4{0.0};
|
||||
T min{std::numeric_limits<T>::max()};
|
||||
T max{std::numeric_limits<T>::min()};
|
||||
};
|
||||
} // namespace celero
|
||||
|
||||
#endif
|
122
celero/celero/TestFixture.cpp
Normal file
122
celero/celero/TestFixture.cpp
Normal file
@ -0,0 +1,122 @@
|
||||
///
|
||||
/// \author John Farrier
|
||||
///
|
||||
/// \copyright Copyright 2015, 2016, 2017, 2018 John Farrier
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
|
||||
#include <assert.h>
|
||||
#include <celero/TestFixture.h>
|
||||
#include <celero/UserDefinedMeasurement.h>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
|
||||
using namespace celero;
|
||||
|
||||
TestFixture::TestFixture()
|
||||
{
|
||||
}
|
||||
|
||||
TestFixture::~TestFixture()
|
||||
{
|
||||
}
|
||||
|
||||
void TestFixture::onExperimentStart(const celero::TestFixture::ExperimentValue&)
|
||||
{
|
||||
}
|
||||
|
||||
void TestFixture::onExperimentEnd()
|
||||
{
|
||||
}
|
||||
|
||||
void TestFixture::setUp(const celero::TestFixture::ExperimentValue&)
|
||||
{
|
||||
}
|
||||
|
||||
void TestFixture::tearDown()
|
||||
{
|
||||
}
|
||||
|
||||
uint64_t TestFixture::run(const uint64_t, const uint64_t iterations, const celero::TestFixture::ExperimentValue& experimentValue)
|
||||
{
|
||||
// This function constitutes one sample consisting of several iterations for a single experiment value.
|
||||
|
||||
if(this->HardCodedMeasurement() == 0)
|
||||
{
|
||||
uint64_t totalTime = 0;
|
||||
|
||||
// Set up the testing fixture.
|
||||
this->setUp(experimentValue);
|
||||
|
||||
// Run the test body for each iterations.
|
||||
auto iterationCounter = iterations;
|
||||
|
||||
// Get the starting time.
|
||||
const auto startTime = celero::timer::GetSystemTime();
|
||||
|
||||
// Count down to zero
|
||||
// Iterations are used when the benchmarks are very fast.
|
||||
// Do not start/stop the timer inside this loop.
|
||||
// The purpose of the loop is to help counter timer quantization/errors.
|
||||
while(iterationCounter--)
|
||||
{
|
||||
this->onExperimentStart(experimentValue);
|
||||
|
||||
this->UserBenchmark();
|
||||
|
||||
this->onExperimentEnd();
|
||||
}
|
||||
|
||||
// See how long it took.
|
||||
totalTime += celero::timer::GetSystemTime() - startTime;
|
||||
|
||||
// Tear down the testing fixture.
|
||||
this->tearDown();
|
||||
|
||||
// Return the duration in microseconds for the given problem size.
|
||||
return totalTime;
|
||||
}
|
||||
|
||||
return this->HardCodedMeasurement();
|
||||
}
|
||||
|
||||
void TestFixture::UserBenchmark()
|
||||
{
|
||||
}
|
||||
|
||||
uint64_t TestFixture::HardCodedMeasurement() const
|
||||
{
|
||||
return uint64_t(0);
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<UserDefinedMeasurement>> TestFixture::getUserDefinedMeasurements() const
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<std::string> TestFixture::getUserDefinedMeasurementNames() const
|
||||
{
|
||||
std::vector<std::string> names;
|
||||
const auto udms = this->getUserDefinedMeasurements();
|
||||
|
||||
if(udms.empty() == false)
|
||||
{
|
||||
for(const auto udm : udms)
|
||||
{
|
||||
names.emplace_back(udm->getName());
|
||||
}
|
||||
}
|
||||
|
||||
return names;
|
||||
}
|
192
celero/celero/TestFixture.h
Normal file
192
celero/celero/TestFixture.h
Normal file
@ -0,0 +1,192 @@
|
||||
#ifndef H_CELERO_TESTFIXTURE_H
|
||||
#define H_CELERO_TESTFIXTURE_H
|
||||
|
||||
///
|
||||
/// \author John Farrier
|
||||
///
|
||||
/// \copyright Copyright 2015, 2016, 2017, 2018 John Farrier
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
|
||||
#include <celero/Export.h>
|
||||
#include <celero/Timer.h>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
// This must be included last.
|
||||
#include <celero/ThreadLocal.h>
|
||||
|
||||
namespace celero
|
||||
{
|
||||
class Benchmark;
|
||||
class UserDefinedMeasurement;
|
||||
|
||||
///
|
||||
/// \class TestFixture
|
||||
///
|
||||
/// \author John Farrier
|
||||
///
|
||||
class CELERO_EXPORT TestFixture
|
||||
{
|
||||
public:
|
||||
///
|
||||
/// Default Constructor.
|
||||
///
|
||||
TestFixture();
|
||||
|
||||
///
|
||||
/// Virtual destructor for inheritance.
|
||||
///
|
||||
virtual ~TestFixture();
|
||||
|
||||
enum class Constants : int64_t
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
#if(_MSC_VER < 1900)
|
||||
NoProblemSpaceValue = -9223372036854775807
|
||||
#else
|
||||
NoProblemSpaceValue = std::numeric_limits<int64_t>::min()
|
||||
#endif
|
||||
#else
|
||||
NoProblemSpaceValue = std::numeric_limits<int64_t>::min()
|
||||
#endif
|
||||
};
|
||||
|
||||
///
|
||||
/// \class ExperimentValue
|
||||
///
|
||||
/// You can derive from this type to add your own information to the experiment value set.
|
||||
///
|
||||
class ExperimentValue
|
||||
{
|
||||
public:
|
||||
ExperimentValue() = default;
|
||||
ExperimentValue(int64_t v) : Value(v){};
|
||||
ExperimentValue(int64_t v, int64_t i) : Value(v), Iterations(i){};
|
||||
|
||||
virtual ~ExperimentValue() = default;
|
||||
|
||||
/// An arbitrary integer value which can be used or translated for use by the test fixture.
|
||||
int64_t Value{0};
|
||||
|
||||
/// The number of iterations to do with this test value. 0 (default) indicates that the default number of iterations set up for the test
|
||||
/// case should be used.
|
||||
int64_t Iterations{0};
|
||||
};
|
||||
|
||||
///
|
||||
/// Allows a test fixture to supply values to use for experiments.
|
||||
///
|
||||
/// This is used to create multiple runs of the same experiment
|
||||
/// and varrying the data set size, for example. The second value
|
||||
/// of the pair is an optional override for the number of iterations
|
||||
/// to be used. If zero is specified, then the default number of
|
||||
/// iterations is used.
|
||||
///
|
||||
/// It is only guaranteed that the constructor is called prior to this function being called.
|
||||
///
|
||||
virtual std::vector<celero::TestFixture::ExperimentValue> getExperimentValues() const
|
||||
{
|
||||
return std::vector<celero::TestFixture::ExperimentValue>();
|
||||
};
|
||||
|
||||
///
|
||||
/// Provide a units result scale of each experiment value.
|
||||
///
|
||||
/// If the value is greater than 0 then additional statistic value will be printed
|
||||
/// in output - [ xxxx units/sec ]. For example for measure speed of
|
||||
/// file IO operations method might return 1024 * 1024 to get megabytes
|
||||
/// per second.
|
||||
///
|
||||
/// It is only guaranteed that the constructor is called prior to this function being called.
|
||||
///
|
||||
virtual double getExperimentValueResultScale() const
|
||||
{
|
||||
return 1.0;
|
||||
};
|
||||
|
||||
///
|
||||
/// Allows the text fixture to run code that will be executed once immediately before the benchmark.
|
||||
///
|
||||
/// Unlike setUp, the evaluation of this function IS included in the total experiment execution
|
||||
/// time.
|
||||
///
|
||||
/// \param x The value for the experiment. This can be ignored if the test does not utilize experiment values.
|
||||
///
|
||||
virtual void onExperimentStart(const celero::TestFixture::ExperimentValue& x);
|
||||
|
||||
///
|
||||
/// Allows the text fixture to run code that will be executed once immediately after the benchmark.
|
||||
/// Unlike tearDown, the evaluation of this function IS included in the total experiment execution
|
||||
/// time.
|
||||
///
|
||||
virtual void onExperimentEnd();
|
||||
|
||||
///
|
||||
/// Set up the test fixture before benchmark execution.
|
||||
///
|
||||
/// This code is NOT included in the benchmark timing.
|
||||
/// It is executed once before all iterations are executed and between each Sample.
|
||||
/// Your experiment should NOT rely on "setUp" methods to be called before EACH experiment run, only between each sample.
|
||||
///
|
||||
/// \param x The celero::TestFixture::ExperimentValue for the experiment. This can be ignored if the test does not utilize experiment values.
|
||||
///
|
||||
virtual void setUp(const celero::TestFixture::ExperimentValue& x);
|
||||
|
||||
///
|
||||
/// Called after test completion to destroy the fixture.
|
||||
///
|
||||
/// This code is NOT included in the benchmark timing.
|
||||
/// It is executed once after all iterations are executed and between each Sample.
|
||||
/// Your experiment should NOT rely on "tearDown" methods to be called after EACH experiment run, only between each sample.
|
||||
///
|
||||
virtual void tearDown();
|
||||
|
||||
///
|
||||
///
|
||||
/// \param threads The number of working threads.
|
||||
/// \param iterations The number of times to loop over the UserBenchmark function.
|
||||
/// \param experimentValue The experiment value to pass in setUp function.
|
||||
///
|
||||
/// \return Returns the number of microseconds the run took.
|
||||
///
|
||||
virtual uint64_t run(uint64_t threads, uint64_t iterations, const celero::TestFixture::ExperimentValue& experimentValue);
|
||||
|
||||
///
|
||||
/// \brief If you want to use user-defined measurements, override this method to return them
|
||||
///
|
||||
/// This method must return a vector of pointers, one per type of user-defined measurement that you want to measure.
|
||||
///
|
||||
virtual std::vector<std::shared_ptr<UserDefinedMeasurement>> getUserDefinedMeasurements() const;
|
||||
|
||||
///
|
||||
/// \brief Returns the names of all user-defined measurements in this fixture.
|
||||
///
|
||||
std::vector<std::string> getUserDefinedMeasurementNames() const;
|
||||
|
||||
protected:
|
||||
/// Executed for each operation the benchmarking test is run.
|
||||
virtual void UserBenchmark();
|
||||
|
||||
///
|
||||
/// Only used for baseline cases. Used to define a hard-coded execution time vs. actually making a measurement.
|
||||
///
|
||||
virtual uint64_t HardCodedMeasurement() const;
|
||||
};
|
||||
} // namespace celero
|
||||
|
||||
#endif
|
83
celero/celero/TestVector.cpp
Normal file
83
celero/celero/TestVector.cpp
Normal file
@ -0,0 +1,83 @@
|
||||
///
|
||||
/// \author John Farrier
|
||||
///
|
||||
/// \copyright Copyright 2015, 2016, 2017, 2018 John Farrier
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
|
||||
#include <celero/Benchmark.h>
|
||||
#include <celero/PimplImpl.h>
|
||||
#include <celero/TestVector.h>
|
||||
#include <algorithm>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
|
||||
using namespace celero;
|
||||
|
||||
///
|
||||
/// \class Impl
|
||||
///
|
||||
class celero::TestVector::Impl
|
||||
{
|
||||
public:
|
||||
Impl() : testVectorMutex(), testVector()
|
||||
{
|
||||
}
|
||||
|
||||
mutable std::mutex testVectorMutex;
|
||||
std::vector<std::shared_ptr<Benchmark>> testVector;
|
||||
};
|
||||
|
||||
TestVector::TestVector() : pimpl()
|
||||
{
|
||||
}
|
||||
|
||||
TestVector& TestVector::Instance()
|
||||
{
|
||||
static TestVector singleton;
|
||||
return singleton;
|
||||
}
|
||||
|
||||
void TestVector::push_back(std::shared_ptr<Benchmark> x)
|
||||
{
|
||||
std::lock_guard<std::mutex> mutexLock(this->pimpl->testVectorMutex);
|
||||
this->pimpl->testVector.push_back(x);
|
||||
}
|
||||
|
||||
size_t TestVector::size() const
|
||||
{
|
||||
std::lock_guard<std::mutex> mutexLock(this->pimpl->testVectorMutex);
|
||||
return this->pimpl->testVector.size();
|
||||
}
|
||||
|
||||
std::shared_ptr<Benchmark> TestVector::operator[](size_t x)
|
||||
{
|
||||
std::lock_guard<std::mutex> mutexLock(this->pimpl->testVectorMutex);
|
||||
return this->pimpl->testVector[x];
|
||||
}
|
||||
|
||||
std::shared_ptr<Benchmark> TestVector::operator[](const std::string& x)
|
||||
{
|
||||
std::lock_guard<std::mutex> mutexLock(this->pimpl->testVectorMutex);
|
||||
|
||||
const auto found = std::find_if(std::begin(this->pimpl->testVector), std::end(this->pimpl->testVector),
|
||||
[x](std::shared_ptr<Benchmark> const& bmark) -> bool { return (bmark->getName() == x); });
|
||||
|
||||
if(found != std::end(this->pimpl->testVector))
|
||||
{
|
||||
return *found;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
64
celero/celero/TestVector.h
Normal file
64
celero/celero/TestVector.h
Normal file
@ -0,0 +1,64 @@
|
||||
#ifndef H_CELERO_TESTVECTOR_H
|
||||
#define H_CELERO_TESTVECTOR_H
|
||||
|
||||
///
|
||||
/// \author John Farrier
|
||||
///
|
||||
/// \copyright Copyright 2015, 2016, 2017, 2018 John Farrier
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
|
||||
#include <celero/Benchmark.h>
|
||||
#include <celero/Export.h>
|
||||
#include <celero/Pimpl.h>
|
||||
#include <functional>
|
||||
|
||||
namespace celero
|
||||
{
|
||||
///
|
||||
/// \class TestVector
|
||||
///
|
||||
/// \author John Farrier
|
||||
///
|
||||
class TestVector
|
||||
{
|
||||
public:
|
||||
static TestVector& Instance();
|
||||
|
||||
void push_back(std::shared_ptr<Benchmark> x);
|
||||
|
||||
size_t size() const;
|
||||
|
||||
std::shared_ptr<Benchmark> operator[](size_t x);
|
||||
std::shared_ptr<Benchmark> operator[](const std::string& x);
|
||||
|
||||
private:
|
||||
///
|
||||
/// Default Constructor
|
||||
///
|
||||
TestVector();
|
||||
|
||||
///
|
||||
/// \brief Pimpl Idiom
|
||||
///
|
||||
class Impl;
|
||||
|
||||
///
|
||||
/// \brief Pimpl Idiom
|
||||
///
|
||||
Pimpl<Impl> pimpl;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
36
celero/celero/ThreadLocal.h
Normal file
36
celero/celero/ThreadLocal.h
Normal file
@ -0,0 +1,36 @@
|
||||
#ifndef H_CELERO_THREADLOCAL_H
|
||||
#define H_CELERO_THREADLOCAL_H
|
||||
|
||||
///
|
||||
/// \author Ivan Shynkarenka
|
||||
///
|
||||
/// \copyright Copyright 2015, 2016, 2017, 2018 John Farrier
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
|
||||
#ifndef thread_local
|
||||
|
||||
#if __STDC_VERSION__ >= 201112 && !defined __STDC_NO_THREADS__
|
||||
#define thread_local _Thread_local
|
||||
#elif defined _WIN32 && (defined _MSC_VER || defined __ICL || defined __DMC__ || defined __BORLANDC__)
|
||||
#define thread_local __declspec(thread)
|
||||
/* note that ICC (linux) and Clang are covered by __GNUC__ */
|
||||
#elif defined __GNUC__ || defined __SUNPRO_C || defined __xlC__
|
||||
#define thread_local __thread
|
||||
#else
|
||||
#error "Cannot define thread_local"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif
|
124
celero/celero/ThreadTestFixture.cpp
Normal file
124
celero/celero/ThreadTestFixture.cpp
Normal file
@ -0,0 +1,124 @@
|
||||
///
|
||||
/// \author Ivan Shynkarenka
|
||||
///
|
||||
/// \copyright Copyright 2015, 2016, 2017, 2018 John Farrier
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
|
||||
#include <celero/ThreadTestFixture.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <celero/PimplImpl.h>
|
||||
#include <algorithm>
|
||||
#include <future>
|
||||
#include <iostream>
|
||||
|
||||
using namespace celero;
|
||||
|
||||
class ThreadTestFixture::Impl
|
||||
{
|
||||
public:
|
||||
static thread_local uint64_t currentCallId;
|
||||
static thread_local uint64_t currentThreadId;
|
||||
std::vector<std::future<void>> futures;
|
||||
};
|
||||
|
||||
thread_local uint64_t ThreadTestFixture::Impl::currentCallId = 0;
|
||||
thread_local uint64_t ThreadTestFixture::Impl::currentThreadId = 0;
|
||||
|
||||
ThreadTestFixture::ThreadTestFixture() : TestFixture()
|
||||
{
|
||||
}
|
||||
|
||||
ThreadTestFixture::~ThreadTestFixture()
|
||||
{
|
||||
}
|
||||
|
||||
void ThreadTestFixture::startThreads(uint64_t threads, uint64_t iterations)
|
||||
{
|
||||
const uint64_t iterationsPerThread = iterations / threads;
|
||||
|
||||
for(uint64_t i = 0; i < threads; ++i)
|
||||
{
|
||||
try
|
||||
{
|
||||
this->pimpl->futures.push_back(
|
||||
// std::async(std::launch::deferred,
|
||||
std::async(std::launch::async, [this, i, iterationsPerThread]() {
|
||||
this->pimpl->currentThreadId = i + 1;
|
||||
for(auto threadIterationCounter = size_t(0); threadIterationCounter < iterationsPerThread;)
|
||||
{
|
||||
this->pimpl->currentCallId = ++threadIterationCounter;
|
||||
this->UserBenchmark();
|
||||
}
|
||||
}));
|
||||
}
|
||||
catch(std::system_error& e)
|
||||
{
|
||||
std::cerr << "Exception. Error Code: " << e.code() << ", " << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ThreadTestFixture::stopThreads()
|
||||
{
|
||||
// This part will be more effective after
|
||||
// wait_for_all() will be avaliable for futures!
|
||||
for(auto& f : this->pimpl->futures)
|
||||
{
|
||||
if(f.valid() == true)
|
||||
{
|
||||
try
|
||||
{
|
||||
f.wait();
|
||||
}
|
||||
catch(std::system_error& e)
|
||||
{
|
||||
std::cerr << "Exception. Error Code: " << e.code() << ", " << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
uint64_t ThreadTestFixture::run(uint64_t threads, uint64_t calls, const celero::TestFixture::ExperimentValue& experimentValue)
|
||||
{
|
||||
if(this->HardCodedMeasurement() == 0)
|
||||
{
|
||||
// Set up the testing fixture.
|
||||
this->setUp(experimentValue);
|
||||
|
||||
// Get the starting time.
|
||||
const auto startTime = celero::timer::GetSystemTime();
|
||||
|
||||
this->onExperimentStart(experimentValue);
|
||||
|
||||
// Start working threads.
|
||||
this->startThreads(threads, calls);
|
||||
|
||||
// Stop working threads.
|
||||
this->stopThreads();
|
||||
|
||||
this->onExperimentEnd();
|
||||
|
||||
const auto endTime = celero::timer::GetSystemTime();
|
||||
|
||||
// Tear down the testing fixture.
|
||||
this->tearDown();
|
||||
|
||||
// Return the duration in microseconds for the given problem size.
|
||||
return (endTime - startTime);
|
||||
}
|
||||
|
||||
return this->HardCodedMeasurement();
|
||||
}
|
75
celero/celero/ThreadTestFixture.h
Normal file
75
celero/celero/ThreadTestFixture.h
Normal file
@ -0,0 +1,75 @@
|
||||
#ifndef H_CELERO_THREADTESTFIXTURE_H
|
||||
#define H_CELERO_THREADTESTFIXTURE_H
|
||||
|
||||
///
|
||||
/// \author Ivan Shynkarenka
|
||||
///
|
||||
/// \copyright Copyright 2015, 2016, 2017, 2018 John Farrier
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
|
||||
#include <celero/Pimpl.h>
|
||||
#include <celero/TestFixture.h>
|
||||
|
||||
namespace celero
|
||||
{
|
||||
class Benchmark;
|
||||
|
||||
///
|
||||
/// \class ThreadTestFixture
|
||||
///
|
||||
/// \author Ivan Shynkarenka
|
||||
///
|
||||
class CELERO_EXPORT ThreadTestFixture : public TestFixture
|
||||
{
|
||||
public:
|
||||
///
|
||||
/// Default Constructor.
|
||||
///
|
||||
ThreadTestFixture();
|
||||
|
||||
///
|
||||
/// Virtual destructor for inheritance.
|
||||
///
|
||||
virtual ~ThreadTestFixture();
|
||||
|
||||
///
|
||||
/// Start threads before benchmark execution.
|
||||
///
|
||||
/// \param threads Count of working threads to start.
|
||||
/// \param calls The total number of times to loop over the UserBenchmark function.
|
||||
///
|
||||
virtual void startThreads(uint64_t threads, uint64_t calls);
|
||||
|
||||
///
|
||||
/// Called after test completion to stop threads.
|
||||
///
|
||||
virtual void stopThreads();
|
||||
|
||||
///
|
||||
/// \param threads The number of working threads.
|
||||
/// \param calls The total number of times to loop over the UserBenchmark function.
|
||||
/// \param experimentValue The experiment value to pass in setUp function.
|
||||
///
|
||||
/// \return Returns the number of microseconds the run took.
|
||||
///
|
||||
uint64_t run(uint64_t threads, uint64_t calls, const celero::TestFixture::ExperimentValue& experimentValue) override;
|
||||
|
||||
private:
|
||||
class Impl;
|
||||
Pimpl<Impl> pimpl;
|
||||
};
|
||||
} // namespace celero
|
||||
|
||||
#endif
|
59
celero/celero/Timer.cpp
Normal file
59
celero/celero/Timer.cpp
Normal file
@ -0,0 +1,59 @@
|
||||
///
|
||||
/// \author John Farrier
|
||||
///
|
||||
/// \copyright Copyright 2015, 2016, 2017, 2018 John Farrier
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
|
||||
#include <celero/Print.h>
|
||||
#include <celero/Timer.h>
|
||||
#include <iostream>
|
||||
|
||||
#ifdef WIN32
|
||||
#include <Windows.h>
|
||||
LARGE_INTEGER QPCFrequency;
|
||||
#else
|
||||
#include <chrono>
|
||||
#endif
|
||||
|
||||
uint64_t celero::timer::GetSystemTime()
|
||||
{
|
||||
#ifdef WIN32
|
||||
LARGE_INTEGER timeStorage;
|
||||
QueryPerformanceCounter(&timeStorage);
|
||||
return static_cast<uint64_t>(timeStorage.QuadPart * 1000000) / static_cast<uint64_t>(QPCFrequency.QuadPart);
|
||||
#else
|
||||
auto timePoint = std::chrono::high_resolution_clock::now();
|
||||
return std::chrono::duration_cast<std::chrono::microseconds>(timePoint.time_since_epoch()).count();
|
||||
#endif
|
||||
}
|
||||
|
||||
double celero::timer::CachePerformanceFrequency(bool quiet)
|
||||
{
|
||||
#ifdef WIN32
|
||||
QueryPerformanceFrequency(&QPCFrequency);
|
||||
auto precision = ((1.0 / static_cast<double>(QPCFrequency.QuadPart)) * 1000000.0);
|
||||
#else
|
||||
auto precision =
|
||||
(static_cast<double>(std::chrono::high_resolution_clock::period::num) / static_cast<double>(std::chrono::high_resolution_clock::period::den))
|
||||
* 1000000.0;
|
||||
#endif
|
||||
|
||||
if(quiet == false)
|
||||
{
|
||||
std::cout << "Timer resolution: " << std::to_string(precision) << " us" << std::endl;
|
||||
}
|
||||
|
||||
return precision;
|
||||
}
|
70
celero/celero/Timer.h
Normal file
70
celero/celero/Timer.h
Normal file
@ -0,0 +1,70 @@
|
||||
#ifndef H_CELERO_TIMER_H
|
||||
#define H_CELERO_TIMER_H
|
||||
|
||||
///
|
||||
/// \author John Farrier
|
||||
///
|
||||
/// \copyright Copyright 2015, 2016, 2017, 2018 John Farrier
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
|
||||
#include <celero/Utilities.h>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace celero
|
||||
{
|
||||
///
|
||||
/// \namespace timer
|
||||
///
|
||||
/// \author John Farrier
|
||||
///
|
||||
/// \brief Provide basic cross-platform timing functions to measure code performance speed.
|
||||
///
|
||||
namespace timer
|
||||
{
|
||||
///
|
||||
/// \brief Retrieves the current time.
|
||||
///
|
||||
/// \author John Farrier
|
||||
///
|
||||
/// \return The time, in ticks.
|
||||
///
|
||||
uint64_t GetSystemTime();
|
||||
|
||||
///
|
||||
/// \brief Converts the gathered system time into seconds.
|
||||
///
|
||||
/// This assumes "x" is a delta and relatively small (easily fits inside of a double).
|
||||
///
|
||||
/// \author John Farrier
|
||||
///
|
||||
/// \param x The time, in ticks.
|
||||
///
|
||||
/// \return The time, in seconds.
|
||||
///
|
||||
constexpr double ConvertSystemTime(const uint64_t x)
|
||||
{
|
||||
return x * celero::UsToSec;
|
||||
}
|
||||
|
||||
///
|
||||
/// On Windows, this caches the frequency of the high performance clock.
|
||||
///
|
||||
/// \return The number of microseconds of precision that we have.
|
||||
///
|
||||
double CachePerformanceFrequency(bool quiet);
|
||||
} // namespace timer
|
||||
} // namespace celero
|
||||
|
||||
#endif
|
76
celero/celero/UserDefinedMeasurement.h
Normal file
76
celero/celero/UserDefinedMeasurement.h
Normal file
@ -0,0 +1,76 @@
|
||||
#ifndef H_CELERO_USERDEFINEDMEASUREMENT_H
|
||||
#define H_CELERO_USERDEFINEDMEASUREMENT_H
|
||||
|
||||
///
|
||||
/// \author Lukas Barth
|
||||
///
|
||||
/// \copyright Copyright 2015, 2016, 2017, 2018 John Farrier
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
|
||||
#include <celero/Export.h>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
namespace celero
|
||||
{
|
||||
class UserDefinedMeasurement;
|
||||
|
||||
///
|
||||
/// \brief Describes, which aggregations should be computed on a user-defined measurement.
|
||||
///
|
||||
/// The string names the aggregation, the UDMAggregateFunction is the function that will be called on the collected vector of user-defined
|
||||
/// measurements.
|
||||
///
|
||||
using UDMAggregationTable = std::vector<std::pair<std::string, std::function<double(void)>>>;
|
||||
|
||||
///
|
||||
/// \class UserDefinedMeasurement
|
||||
///
|
||||
/// Base class that the user must derive user-defined measurements from.
|
||||
///
|
||||
/// \author Lukas Barth
|
||||
///
|
||||
class CELERO_EXPORT UserDefinedMeasurement
|
||||
{
|
||||
public:
|
||||
///
|
||||
/// \brief Must be implemented by the user. Must return a specification which aggregations the user wants to be computed.
|
||||
///
|
||||
virtual UDMAggregationTable getAggregationInfo() const = 0;
|
||||
|
||||
///
|
||||
/// \brief Must be implemented by the user. Must return the name of this user-defined measurement.
|
||||
///
|
||||
virtual std::string getName() const = 0;
|
||||
|
||||
///
|
||||
/// \brief Combine the results of two user defined measurements.
|
||||
///
|
||||
/// As TestFixture classes are created and destroyed, this provides a mechanisim to preserve data. Internally, this function is used so that
|
||||
/// each unique set of (group, experiment, problem space) has its own combined set of user defined measurements.
|
||||
///
|
||||
virtual void merge(const UserDefinedMeasurement* const x) = 0;
|
||||
|
||||
protected:
|
||||
// Class may never be directly instantiated
|
||||
UserDefinedMeasurement() = default;
|
||||
};
|
||||
|
||||
} // namespace celero
|
||||
|
||||
#endif
|
94
celero/celero/UserDefinedMeasurementCollector.cpp
Normal file
94
celero/celero/UserDefinedMeasurementCollector.cpp
Normal file
@ -0,0 +1,94 @@
|
||||
///
|
||||
/// \author Lukas Barth
|
||||
///
|
||||
/// \copyright Copyright 2015, 2016, 2017, 2018 John Farrier
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
|
||||
#include <assert.h>
|
||||
#include <celero/TestFixture.h>
|
||||
#include <celero/UserDefinedMeasurementCollector.h>
|
||||
|
||||
using namespace celero;
|
||||
|
||||
UserDefinedMeasurementCollector::UserDefinedMeasurementCollector(std::shared_ptr<TestFixture> fixture)
|
||||
{
|
||||
const auto udm = fixture->getUserDefinedMeasurementNames();
|
||||
|
||||
if(udm.empty() == false)
|
||||
{
|
||||
for(auto name : fixture->getUserDefinedMeasurementNames())
|
||||
{
|
||||
this->collected[name] = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UserDefinedMeasurementCollector::collect(std::shared_ptr<TestFixture> fixture)
|
||||
{
|
||||
const auto udms = fixture->getUserDefinedMeasurements();
|
||||
|
||||
if(udms.empty() == false)
|
||||
{
|
||||
for(auto udm : udms)
|
||||
{
|
||||
if(this->collected[udm->getName()] == nullptr)
|
||||
{
|
||||
this->collected[udm->getName()] = udm;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->collected[udm->getName()]->merge(&*udm);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::string> UserDefinedMeasurementCollector::getFields(std::shared_ptr<TestFixture> fixture) const
|
||||
{
|
||||
std::vector<std::string> fields;
|
||||
const auto udms = fixture->getUserDefinedMeasurements();
|
||||
|
||||
if(udms.empty() == false)
|
||||
{
|
||||
for(auto udm : udms)
|
||||
{
|
||||
for(const auto& aggDesc : udm->getAggregationInfo())
|
||||
{
|
||||
fields.emplace_back(std::string(udm->getName()) + std::string(" ") + std::string(aggDesc.first));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return fields;
|
||||
}
|
||||
|
||||
std::vector<std::pair<std::string, double>> UserDefinedMeasurementCollector::getAggregateValues() const
|
||||
{
|
||||
std::vector<std::pair<std::string, double>> aggregates;
|
||||
|
||||
for(const auto& collectedEntry : this->collected)
|
||||
{
|
||||
const auto name = collectedEntry.first;
|
||||
const auto collectedUDMs = collectedEntry.second;
|
||||
|
||||
for(const auto& aggDesc : collectedUDMs->getAggregationInfo())
|
||||
{
|
||||
const auto fieldName = name + std::string(" ") + aggDesc.first;
|
||||
aggregates.emplace_back(fieldName, (aggDesc.second)());
|
||||
}
|
||||
}
|
||||
|
||||
return aggregates;
|
||||
}
|
46
celero/celero/UserDefinedMeasurementCollector.h
Normal file
46
celero/celero/UserDefinedMeasurementCollector.h
Normal file
@ -0,0 +1,46 @@
|
||||
#ifndef H_CELERO_USERDEFINEDMEASUREMENTCOLLECTOR_H
|
||||
#define H_CELERO_USERDEFINEDMEASUREMENTCOLLECTOR_H
|
||||
|
||||
///
|
||||
/// \author Lukas Barth
|
||||
///
|
||||
/// \copyright Copyright 2015, 2016, 2017, 2018 John Farrier
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
|
||||
#include <celero/UserDefinedMeasurement.h>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace celero
|
||||
{
|
||||
///
|
||||
/// \class UserDefinedMeasurementCollector
|
||||
///
|
||||
/// \author Lukas Barth
|
||||
///
|
||||
class UserDefinedMeasurementCollector
|
||||
{
|
||||
public:
|
||||
UserDefinedMeasurementCollector(std::shared_ptr<TestFixture> fixture);
|
||||
|
||||
void collect(std::shared_ptr<TestFixture> fixture);
|
||||
std::vector<std::string> getFields(std::shared_ptr<TestFixture> fixture) const;
|
||||
std::vector<std::pair<std::string, double>> getAggregateValues() const;
|
||||
|
||||
private:
|
||||
std::unordered_map<std::string, std::shared_ptr<celero::UserDefinedMeasurement>> collected;
|
||||
};
|
||||
} // namespace celero
|
||||
|
||||
#endif
|
182
celero/celero/UserDefinedMeasurementTemplate.h
Normal file
182
celero/celero/UserDefinedMeasurementTemplate.h
Normal file
@ -0,0 +1,182 @@
|
||||
#ifndef H_CELERO_USERDEFINEDMEASUREMENTTEMPLATE_H
|
||||
#define H_CELERO_USERDEFINEDMEASUREMENTTEMPLATE_H
|
||||
|
||||
///
|
||||
/// \author Lukas Barth, John Farrier
|
||||
///
|
||||
/// \copyright Copyright 2015, 2016, 2017, 2018 John Farrier
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
|
||||
#include <celero/Statistics.h>
|
||||
#include <celero/UserDefinedMeasurement.h>
|
||||
#include <numeric>
|
||||
#include <type_traits>
|
||||
|
||||
namespace celero
|
||||
{
|
||||
///
|
||||
/// \class UserDefinedMeasurementTemplate
|
||||
///
|
||||
/// Base class that the user must derive user-defined measurements from.
|
||||
///
|
||||
/// \author Lukas Barth, John Farrier
|
||||
///
|
||||
template <typename T>
|
||||
class UserDefinedMeasurementTemplate : public UserDefinedMeasurement
|
||||
{
|
||||
static_assert(std::is_arithmetic<T>::value, "UserDefinedMeasurementTemplate requres an arithmetic type.");
|
||||
|
||||
public:
|
||||
///
|
||||
/// Default constructor
|
||||
///
|
||||
UserDefinedMeasurementTemplate() = default;
|
||||
|
||||
///
|
||||
/// Default destructor
|
||||
///
|
||||
virtual ~UserDefinedMeasurementTemplate() = default;
|
||||
|
||||
///
|
||||
/// \brief Must be implemented by the user. Must return a specification which aggregations the user wants to be computed.
|
||||
///
|
||||
virtual UDMAggregationTable getAggregationInfo() const override
|
||||
{
|
||||
UDMAggregationTable table;
|
||||
|
||||
if(this->reportSize() == true)
|
||||
{
|
||||
table.push_back({"# Samp", [this]() { return static_cast<double>(this->getStatistics().getSize()); }});
|
||||
}
|
||||
|
||||
if(this->reportMean() == true)
|
||||
{
|
||||
table.push_back({"Mean", [this]() { return this->getStatistics().getMean(); }});
|
||||
}
|
||||
|
||||
if(this->reportVariance() == true)
|
||||
{
|
||||
table.push_back({"Var", [this]() { return this->getStatistics().getVariance(); }});
|
||||
}
|
||||
|
||||
if(this->reportStandardDeviation() == true)
|
||||
{
|
||||
table.push_back({"StdDev", [this]() { return this->getStatistics().getStandardDeviation(); }});
|
||||
}
|
||||
|
||||
if(this->reportSkewness() == true)
|
||||
{
|
||||
table.push_back({"Skew", [this]() { return this->getStatistics().getSkewness(); }});
|
||||
}
|
||||
|
||||
if(this->reportKurtosis() == true)
|
||||
{
|
||||
table.push_back({"Kurtosis", [this]() { return this->getStatistics().getKurtosis(); }});
|
||||
}
|
||||
|
||||
if(this->reportZScore() == true)
|
||||
{
|
||||
table.push_back({"ZScore", [this]() { return this->getStatistics().getZScore(); }});
|
||||
}
|
||||
|
||||
if(this->reportMin() == true)
|
||||
{
|
||||
table.push_back({"Min", [this]() { return static_cast<double>(this->getStatistics().getMin()); }});
|
||||
}
|
||||
|
||||
if(this->reportMax() == true)
|
||||
{
|
||||
table.push_back({"Max", [this]() { return static_cast<double>(this->getStatistics().getMax()); }});
|
||||
}
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief You must call this method from your fixture to add a measurement
|
||||
///
|
||||
void addValue(T x)
|
||||
{
|
||||
this->stats.addSample(x);
|
||||
}
|
||||
|
||||
///
|
||||
/// Preserve measurements within a group/experiment/problem space set.
|
||||
///
|
||||
virtual void merge(const UserDefinedMeasurement* const x) override
|
||||
{
|
||||
const auto toMerge = dynamic_cast<const UserDefinedMeasurementTemplate<T>* const>(x);
|
||||
this->stats += toMerge->stats;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual bool reportSize() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool reportMean() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool reportVariance() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool reportStandardDeviation() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool reportSkewness() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool reportKurtosis() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool reportZScore() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool reportMin() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool reportMax() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
const Statistics<T>& getStatistics() const
|
||||
{
|
||||
return this->stats;
|
||||
}
|
||||
|
||||
private:
|
||||
/// Continuously gathers statistics without having to retain data history.
|
||||
Statistics<T> stats;
|
||||
};
|
||||
|
||||
} // namespace celero
|
||||
|
||||
#endif
|
67
celero/celero/Utilities.cpp
Normal file
67
celero/celero/Utilities.cpp
Normal file
@ -0,0 +1,67 @@
|
||||
///
|
||||
/// \author John Farrier
|
||||
///
|
||||
/// \copyright Copyright 2015, 2016, 2017, 2018 John Farrier
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
|
||||
#include <celero/Print.h>
|
||||
#include <celero/Utilities.h>
|
||||
|
||||
#ifdef WIN32
|
||||
#include <Windows.h>
|
||||
|
||||
#include <PowrProf.h>
|
||||
#endif
|
||||
|
||||
#ifdef max
|
||||
#undef max
|
||||
#endif
|
||||
|
||||
#include <limits>
|
||||
#include <random>
|
||||
|
||||
template <>
|
||||
void celero::DoNotOptimizeAway(std::function<void(void)>&& x)
|
||||
{
|
||||
x();
|
||||
|
||||
// We must always do this test, but it will never pass.
|
||||
static auto ttid = std::this_thread::get_id();
|
||||
if(ttid == std::thread::id())
|
||||
{
|
||||
// This forces the value to never be optimized away
|
||||
// by taking a reference then using it.
|
||||
const auto* p = &x;
|
||||
putchar(*reinterpret_cast<const char*>(p));
|
||||
|
||||
// If we do get here, kick out because something has gone wrong.
|
||||
std::abort();
|
||||
}
|
||||
}
|
||||
|
||||
int celero::Random()
|
||||
{
|
||||
// http://en.cppreference.com/w/cpp/numeric/random/uniform_int_distribution
|
||||
|
||||
// Will be used to obtain a seed for the random number engine
|
||||
static std::random_device rd;
|
||||
|
||||
// Standard mersenne_twister_engine seeded with rd()
|
||||
static std::mt19937 gen(rd());
|
||||
|
||||
static std::uniform_int_distribution<> dis(std::numeric_limits<int>::lowest(), std::numeric_limits<int>::max());
|
||||
|
||||
return dis(gen);
|
||||
}
|
156
celero/celero/Utilities.h
Normal file
156
celero/celero/Utilities.h
Normal file
@ -0,0 +1,156 @@
|
||||
#ifndef H_CELERO_UTILITIES_H
|
||||
#define H_CELERO_UTILITIES_H
|
||||
|
||||
///
|
||||
/// \author John Farrier
|
||||
///
|
||||
/// \copyright Copyright 2015, 2016, 2017, 2018 John Farrier
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
|
||||
#ifndef WIN32
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <functional>
|
||||
#include <thread>
|
||||
|
||||
#include <celero/Export.h>
|
||||
|
||||
namespace celero
|
||||
{
|
||||
///
|
||||
/// \func DoNotOptimizeAway
|
||||
///
|
||||
/// Used to prevent compiler optimization of a variable
|
||||
/// that performs no real purpose other than to participate
|
||||
/// in a benchmark
|
||||
///
|
||||
/// Consider the following trivial benchmark:
|
||||
///
|
||||
/// \code
|
||||
/// BASELINE(...)
|
||||
/// {
|
||||
/// int x = 0;
|
||||
///
|
||||
/// for(int i = 0; i < 64; i++)
|
||||
/// {
|
||||
/// x += i;
|
||||
/// }
|
||||
/// }
|
||||
/// \endcode
|
||||
///
|
||||
/// Using Ubuntu clang v3.0, the resultant assembly is highly optimized
|
||||
/// as one might expect, but not terribly useful for baselining:
|
||||
///
|
||||
/// \verbatim
|
||||
/// movl $2016, %eax # imm = 0x7E0
|
||||
/// ret
|
||||
/// \endverbatim
|
||||
///
|
||||
/// Now, replace the inner loop with a call to DoNotOptimizeAway:
|
||||
///
|
||||
/// \code
|
||||
/// DoNotOptimizeAway(x += i);
|
||||
/// \endcode
|
||||
///
|
||||
/// The result is now a loop which is meaningful for establishing a
|
||||
/// baseline.
|
||||
///
|
||||
/// \verbatim
|
||||
/// xorl %ecx, %ecx
|
||||
/// xorl %eax, %eax
|
||||
/// .LBB0_1: # =>This Inner Loop Header: Depth=1
|
||||
/// addl %ecx, %eax
|
||||
/// incl %ecx
|
||||
/// cmpl $64, %ecx
|
||||
/// jne .LBB0_1
|
||||
/// ret
|
||||
/// \endverbatim
|
||||
///
|
||||
/// GCC 4.8 gives similar results.
|
||||
///
|
||||
/// gcc.godbolt.org permalink: http://goo.gl/lsngwX
|
||||
///
|
||||
/// Folly uses a simple bit of inline assembly:
|
||||
/// > template <class T>
|
||||
/// > void doNotOptimizeAway(T&& datum) {
|
||||
/// > asm volatile("" : "+r" (datum));
|
||||
/// >}
|
||||
///
|
||||
/// It would be great if that were portable with respect to both compilers and 32/64-bit targets.
|
||||
///
|
||||
template <class T>
|
||||
void DoNotOptimizeAway(T&& x)
|
||||
{
|
||||
static auto ttid = std::this_thread::get_id();
|
||||
if(ttid == std::thread::id())
|
||||
{
|
||||
// This forces the value to never be optimized away
|
||||
// by taking a reference then using it.
|
||||
const auto* p = &x;
|
||||
putchar(*reinterpret_cast<const char*>(p));
|
||||
|
||||
// If we do get here, kick out because something has gone wrong.
|
||||
std::abort();
|
||||
}
|
||||
}
|
||||
|
||||
/// Specialization for std::function objects which return a value.
|
||||
template <class T>
|
||||
void DoNotOptimizeAway(std::function<T(void)>&& x)
|
||||
{
|
||||
volatile auto foo = x();
|
||||
|
||||
static auto ttid = std::this_thread::get_id();
|
||||
if(ttid == std::thread::id())
|
||||
{
|
||||
// This forces the value to never be optimized away
|
||||
// by taking a reference then using it.
|
||||
const auto* p = &foo + &x;
|
||||
putchar(*reinterpret_cast<const char*>(p));
|
||||
|
||||
// If we do get here, kick out because something has gone wrong.
|
||||
std::abort();
|
||||
}
|
||||
}
|
||||
|
||||
/// Specialization for std::function objects which return void.
|
||||
template <>
|
||||
CELERO_EXPORT void DoNotOptimizeAway(std::function<void(void)>&& x);
|
||||
|
||||
///
|
||||
/// Quick definition of the number of microseconds per second.
|
||||
///
|
||||
constexpr uint64_t UsPerSec(1000000);
|
||||
|
||||
///
|
||||
/// Conversion from Microseconds to Seconds.
|
||||
///
|
||||
constexpr double UsToSec{1.0e-6};
|
||||
|
||||
///
|
||||
/// Drop-in replacement for std::rand();
|
||||
///
|
||||
CELERO_EXPORT int Random();
|
||||
} // namespace celero
|
||||
|
||||
#endif
|
214
celero/grasp_els.cpp
Normal file
214
celero/grasp_els.cpp
Normal file
@ -0,0 +1,214 @@
|
||||
#include <algorithm>
|
||||
#include <random>
|
||||
|
||||
#include <rosa/els.h>
|
||||
#include <rosa/grasp.h>
|
||||
|
||||
#include <muscles/descent.h>
|
||||
#include <muscles/move2opt.h>
|
||||
#include <muscles/rgreedy.h>
|
||||
|
||||
#include <tsp/problem.h>
|
||||
#include <tsp/solution.h>
|
||||
#include <tsp/tsp.h>
|
||||
|
||||
#include "celero/Celero.h"
|
||||
#include "inc/udm.h"
|
||||
|
||||
namespace {
|
||||
|
||||
namespace bench {
|
||||
|
||||
constexpr std::size_t SAMPLES = 10;
|
||||
constexpr std::size_t ITERATIONS = 1;
|
||||
|
||||
tsp::Solution selectMin(tsp::Solution const&a, tsp::Solution const&b) { return a<b? a:b; }
|
||||
|
||||
}
|
||||
|
||||
|
||||
class GraspElsFixture: public celero::TestFixture {
|
||||
std::shared_ptr<tsp::Problem> _problem;
|
||||
std::shared_ptr<GetRusageUDM> _getRusageUDM;
|
||||
|
||||
GetRusage _getRusage;
|
||||
|
||||
public:
|
||||
static constexpr unsigned graspN = 128;
|
||||
static constexpr unsigned elsIterMax = 5;
|
||||
static constexpr unsigned elsGen = 10;
|
||||
|
||||
static auto rgreedy() { return RGreedy<tsp::Solution>{2}; }
|
||||
|
||||
public:
|
||||
GraspElsFixture(): _getRusageUDM{new GetRusageUDM} {}
|
||||
|
||||
void setUp(ExperimentValue const&) override {
|
||||
tsp::Tsp tspData{"../data/dj38"};
|
||||
_problem.reset(new tsp::Problem{tspData.points()});
|
||||
|
||||
_getRusage.start(bench::ITERATIONS);
|
||||
}
|
||||
|
||||
void tearDown() override {
|
||||
_getRusage.stop();
|
||||
_getRusageUDM->addValue(_getRusage.get());
|
||||
}
|
||||
|
||||
// std::vector<std::shared_ptr<celero::UserDefinedMeasurement>> getUserDefinedMeasurements() const override {
|
||||
// return {_getRusageUDM};
|
||||
// }
|
||||
|
||||
public:
|
||||
tsp::Problem const&problem() const { return *_problem; }
|
||||
|
||||
};
|
||||
|
||||
|
||||
using RNG = std::mt19937;
|
||||
|
||||
auto hwElsGen(tsp::Solution const&solution, RNG &rng) {
|
||||
return Descent{}(Move2Opt{}(solution, rng));
|
||||
}
|
||||
|
||||
auto hwElsInner(tsp::Solution const&solution, RNG &rng) {
|
||||
tsp::Solution best;
|
||||
|
||||
if(GraspElsFixture::elsGen)
|
||||
best = hwElsGen(solution, rng);
|
||||
for(std::size_t i = 1; i < GraspElsFixture::elsGen; ++i) {
|
||||
tsp::Solution current = hwElsGen(solution, rng);
|
||||
best = bench::selectMin(std::move(best), std::move(current));
|
||||
}
|
||||
|
||||
return best;
|
||||
}
|
||||
|
||||
auto hwEls(tsp::Solution const&solution, RNG &rng) {
|
||||
tsp::Solution best = Descent{}(solution);
|
||||
|
||||
for(std::size_t i = 0; i < GraspElsFixture::elsIterMax; ++i) {
|
||||
tsp::Solution current = hwElsInner(best, rng);
|
||||
best = bench::selectMin(std::move(best), std::move(current));
|
||||
}
|
||||
|
||||
return best;
|
||||
}
|
||||
|
||||
auto hwGraspGen(tsp::Problem const&problem, RNG &rng) {
|
||||
return hwEls(GraspElsFixture::rgreedy()(problem, rng), rng);
|
||||
}
|
||||
|
||||
auto hwGraspEls(tsp::Problem const&problem, RNG &rng) {
|
||||
tsp::Solution best;
|
||||
|
||||
if(GraspElsFixture::graspN)
|
||||
best = hwGraspGen(problem, rng);
|
||||
for(std::size_t i = 1; i < GraspElsFixture::graspN; ++i) {
|
||||
tsp::Solution current = hwGraspGen(problem, rng);
|
||||
best = bench::selectMin(std::move(best), std::move(current));
|
||||
}
|
||||
|
||||
return best;
|
||||
}
|
||||
|
||||
template<std::size_t K>
|
||||
auto hwGraspElsPar(tsp::Problem const&problem, RNG &rng) {
|
||||
std::size_t const nThreads = std::min<std::size_t>(K, GraspElsFixture::graspN);
|
||||
std::size_t const step = GraspElsFixture::graspN/nThreads;
|
||||
std::size_t remain = GraspElsFixture::graspN - step*nThreads;
|
||||
|
||||
tsp::Solution best;
|
||||
|
||||
std::vector<std::thread> threads{nThreads-1};
|
||||
std::vector<tsp::Solution> solutions(nThreads);
|
||||
|
||||
for(std::size_t i{}; i < (nThreads-1); ++i) {
|
||||
std::size_t offset = !!remain;
|
||||
remain -= offset;
|
||||
|
||||
threads[i] = std::thread{
|
||||
[&,i,step=step+offset](auto const&problem, auto rng) {
|
||||
tsp::Solution &s = solutions[i];
|
||||
|
||||
for(std::size_t j{}; j < step; ++j) {
|
||||
tsp::Solution cur = hwGraspGen(problem, rng);
|
||||
s = bench::selectMin(std::move(s), std::move(cur));
|
||||
}
|
||||
},
|
||||
std::cref(problem), rng
|
||||
};
|
||||
}
|
||||
|
||||
{
|
||||
tsp::Solution &s = solutions[nThreads-1];
|
||||
|
||||
for(std::size_t j{}; j < step; ++j) {
|
||||
tsp::Solution cur = hwGraspGen(problem, rng);
|
||||
s = bench::selectMin(std::move(s), std::move(cur));
|
||||
}
|
||||
}
|
||||
|
||||
for(auto &thread: threads) thread.join();
|
||||
|
||||
best = *std::min_element(std::begin(solutions), std::end(solutions));
|
||||
|
||||
return best;
|
||||
}
|
||||
|
||||
using ELS = rosa::SkelEls<
|
||||
tsp::Solution,
|
||||
Descent,
|
||||
Move2Opt, Descent, FN(bench::selectMin)
|
||||
>;
|
||||
|
||||
using GRASPxELS = rosa::SkelGrasp<
|
||||
tsp::Problem, tsp::Solution,
|
||||
RGreedy<tsp::Solution>, ELS,
|
||||
FN(bench::selectMin)
|
||||
>;
|
||||
|
||||
}
|
||||
|
||||
BASELINE_F(GraspEls_Seq, Handwritten, GraspElsFixture, bench::SAMPLES, bench::ITERATIONS) {
|
||||
RNG rng;
|
||||
|
||||
celero::DoNotOptimizeAway(
|
||||
hwGraspEls(problem(), rng)
|
||||
);
|
||||
}
|
||||
|
||||
BENCHMARK_F(GraspEls_Seq, Skeleton, GraspElsFixture, bench::SAMPLES, bench::ITERATIONS) {
|
||||
auto graspEls = alsk::implement<alsk::exec::Sequential, GRASPxELS>();
|
||||
graspEls.skeleton.task.task<0>() = rgreedy();
|
||||
graspEls.skeleton.task.task<1>().task<1>().n = elsIterMax;
|
||||
graspEls.skeleton.task.task<1>().task<1>().task.n = elsGen;
|
||||
graspEls.skeleton.n = graspN;
|
||||
|
||||
celero::DoNotOptimizeAway(
|
||||
graspEls(problem())
|
||||
);
|
||||
}
|
||||
|
||||
/* *** */
|
||||
|
||||
BASELINE_F(GraspEls_Par, Handwritten, GraspElsFixture, bench::SAMPLES, bench::ITERATIONS) {
|
||||
RNG rng;
|
||||
|
||||
celero::DoNotOptimizeAway(
|
||||
hwGraspElsPar<2>(problem(), rng)
|
||||
);
|
||||
}
|
||||
|
||||
BENCHMARK_F(GraspEls_Par, Skeleton, GraspElsFixture, bench::SAMPLES, bench::ITERATIONS) {
|
||||
auto graspEls = alsk::implement<alsk::exec::FirstLevelEqui, GRASPxELS>();
|
||||
graspEls.executor.cores = 4;
|
||||
graspEls.skeleton.task.task<0>() = rgreedy();
|
||||
graspEls.skeleton.task.task<1>().task<1>().n = elsIterMax;
|
||||
graspEls.skeleton.task.task<1>().task<1>().task.n = elsGen;
|
||||
graspEls.skeleton.n = graspN;
|
||||
|
||||
celero::DoNotOptimizeAway(
|
||||
graspEls(problem())
|
||||
);
|
||||
}
|
41
celero/inc/udm.h
Normal file
41
celero/inc/udm.h
Normal file
@ -0,0 +1,41 @@
|
||||
#ifndef BENCH_INC_UDM_H
|
||||
#define BENCH_INC_UDM_H
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
|
||||
#include "../celero/Celero.h"
|
||||
|
||||
class GetRusageUDM: public celero::UserDefinedMeasurementTemplate<std::size_t> {
|
||||
std::string getName() const override { return "time"; }
|
||||
|
||||
bool reportSize() const override { return false; }
|
||||
// bool reportMean() const override { return false; }
|
||||
bool reportVariance() const override { return false; }
|
||||
bool reportStandardDeviation() const override { return false; }
|
||||
bool reportSkewness() const override { return false; }
|
||||
bool reportKurtosis() const override { return false; }
|
||||
bool reportZScore() const override { return false; }
|
||||
bool reportMin() const override { return false; }
|
||||
bool reportMax() const override { return false; }
|
||||
};
|
||||
|
||||
class GetRusage {
|
||||
int _who;
|
||||
struct rusage _begin, _end;
|
||||
int _iterations;
|
||||
|
||||
public:
|
||||
explicit GetRusage(int who = RUSAGE_SELF): _who{who} {}
|
||||
void start(int iterations) { _iterations = iterations; getrusage(_who, &_begin); }
|
||||
void stop() { getrusage(_who, &_end); }
|
||||
|
||||
std::size_t get() {
|
||||
auto begin = _begin.ru_utime, end = _end.ru_utime;
|
||||
auto totalUs = (end.tv_sec - begin.tv_sec) * 1e6 + (end.tv_usec - begin.tv_usec);
|
||||
return totalUs/_iterations;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#endif
|
3
celero/main.cpp
Normal file
3
celero/main.cpp
Normal file
@ -0,0 +1,3 @@
|
||||
#include "celero/Celero.h"
|
||||
|
||||
CELERO_MAIN
|
49
data/dj38
Normal file
49
data/dj38
Normal file
@ -0,0 +1,49 @@
|
||||
NAME: dj38
|
||||
COMMENT : 38 locations in Djibouti
|
||||
COMMENT : Derived from National Imagery and Mapping Agency data
|
||||
COMMENT : This file is a corrected version of dj89, where duplications
|
||||
COMMENT: have been removed. Thanks to Jay Muthuswamy and others for
|
||||
COMMENT: requesting data sets without duplications.
|
||||
TYPE: TSP
|
||||
DIMENSION: 38
|
||||
EDGE_WEIGHT_TYPE: EUC_2D
|
||||
NODE_COORD_SECTION
|
||||
1 11003.611100 42102.500000
|
||||
2 11108.611100 42373.888900
|
||||
3 11133.333300 42885.833300
|
||||
4 11155.833300 42712.500000
|
||||
5 11183.333300 42933.333300
|
||||
6 11297.500000 42853.333300
|
||||
7 11310.277800 42929.444400
|
||||
8 11416.666700 42983.333300
|
||||
9 11423.888900 43000.277800
|
||||
10 11438.333300 42057.222200
|
||||
11 11461.111100 43252.777800
|
||||
12 11485.555600 43187.222200
|
||||
13 11503.055600 42855.277800
|
||||
14 11511.388900 42106.388900
|
||||
15 11522.222200 42841.944400
|
||||
16 11569.444400 43136.666700
|
||||
17 11583.333300 43150.000000
|
||||
18 11595.000000 43148.055600
|
||||
19 11600.000000 43150.000000
|
||||
20 11690.555600 42686.666700
|
||||
21 11715.833300 41836.111100
|
||||
22 11751.111100 42814.444400
|
||||
23 11770.277800 42651.944400
|
||||
24 11785.277800 42884.444400
|
||||
25 11822.777800 42673.611100
|
||||
26 11846.944400 42660.555600
|
||||
27 11963.055600 43290.555600
|
||||
28 11973.055600 43026.111100
|
||||
29 12058.333300 42195.555600
|
||||
30 12149.444400 42477.500000
|
||||
31 12286.944400 43355.555600
|
||||
32 12300.000000 42433.333300
|
||||
33 12355.833300 43156.388900
|
||||
34 12363.333300 43189.166700
|
||||
35 12372.777800 42711.388900
|
||||
36 12386.666700 43334.722200
|
||||
37 12421.666700 42895.555600
|
||||
38 12645.000000 42973.333300
|
||||
|
10
data/foo
Normal file
10
data/foo
Normal file
@ -0,0 +1,10 @@
|
||||
NAME: foo
|
||||
TYPE: TSP
|
||||
DIMENSION: 5
|
||||
EDGE_WEIGHT_TYPE: EUC_2D
|
||||
NODE_COORD_SECTION
|
||||
1 0 0
|
||||
2 0 10
|
||||
3 10 0
|
||||
4 10 10
|
||||
5 6 6
|
21
data/foo16
Normal file
21
data/foo16
Normal file
@ -0,0 +1,21 @@
|
||||
NAME: foo16
|
||||
TYPE: TSP
|
||||
DIMENSION: 16
|
||||
EDGE_WEIGHT_TYPE: EUC_2D
|
||||
NODE_COORD_SECTION
|
||||
1 1 1
|
||||
2 9 9
|
||||
3 1 2
|
||||
4 9 8
|
||||
5 3 3
|
||||
6 5 7
|
||||
7 2 1
|
||||
8 12 9
|
||||
9 1 3
|
||||
10 6 11
|
||||
11 4 1
|
||||
12 11 2
|
||||
13 4 6
|
||||
14 7 5
|
||||
15 12 3
|
||||
16 9 5
|
37
data/foo32
Normal file
37
data/foo32
Normal file
@ -0,0 +1,37 @@
|
||||
NAME: foo32
|
||||
TYPE: TSP
|
||||
DIMENSION: 32
|
||||
EDGE_WEIGHT_TYPE: EUC_2D
|
||||
NODE_COORD_SECTION
|
||||
1 1 1
|
||||
2 9 9
|
||||
3 1 2
|
||||
4 9 8
|
||||
5 3 3
|
||||
6 5 7
|
||||
7 2 1
|
||||
8 12 9
|
||||
9 1 3
|
||||
10 6 11
|
||||
11 4 1
|
||||
12 11 2
|
||||
13 4 6
|
||||
14 7 5
|
||||
15 12 3
|
||||
16 9 5
|
||||
17 8 3
|
||||
18 10 6
|
||||
19 2 8
|
||||
20 8 9
|
||||
21 2 4
|
||||
22 16 8
|
||||
23 13 4
|
||||
24 8 15
|
||||
25 4 12
|
||||
26 7 13
|
||||
27 3 8
|
||||
28 13 2
|
||||
29 8 1
|
||||
30 15 3
|
||||
31 11 6
|
||||
32 12 4
|
236
data/gr229
Normal file
236
data/gr229
Normal file
@ -0,0 +1,236 @@
|
||||
NAME: gr229
|
||||
TYPE: TSP
|
||||
COMMENT: Asia/Australia-Subproblem of 666-city TSP (Groetschel)
|
||||
DIMENSION: 229
|
||||
EDGE_WEIGHT_TYPE: GEO
|
||||
DISPLAY_DATA_TYPE: COORD_DISPLAY
|
||||
NODE_COORD_SECTION
|
||||
1 68.58 33.05
|
||||
2 64.34 40.32
|
||||
3 59.55 30.15
|
||||
4 59.25 24.45
|
||||
5 56.57 24.06
|
||||
6 54.43 20.30
|
||||
7 54.41 25.19
|
||||
8 53.54 27.34
|
||||
9 49.50 24.00
|
||||
10 50.26 30.31
|
||||
11 46.28 30.44
|
||||
12 55.45 37.35
|
||||
13 56.20 44.00
|
||||
14 55.45 49.08
|
||||
15 53.12 50.09
|
||||
16 51.40 39.10
|
||||
17 50.00 36.15
|
||||
18 48.27 34.59
|
||||
19 44.36 33.32
|
||||
20 47.14 39.42
|
||||
21 48.44 44.25
|
||||
22 46.21 48.03
|
||||
23 41.43 44.49
|
||||
24 40.11 44.30
|
||||
25 40.23 49.51
|
||||
26 58.00 56.15
|
||||
27 56.51 60.36
|
||||
28 67.27 63.58
|
||||
29 69.20 88.06
|
||||
30 55.00 73.24
|
||||
31 55.02 82.55
|
||||
32 56.01 92.50
|
||||
33 49.50 73.10
|
||||
34 43.15 76.57
|
||||
35 41.20 69.18
|
||||
36 39.40 66.48
|
||||
37 38.35 68.48
|
||||
38 43.48 87.35
|
||||
39 52.16 104.20
|
||||
40 47.55 106.53
|
||||
41 52.03 113.30
|
||||
42 62.13 129.49
|
||||
43 64.45 177.29
|
||||
44 53.01 158.39
|
||||
45 59.34 150.48
|
||||
46 50.17 127.32
|
||||
47 50.35 137.02
|
||||
48 48.27 135.06
|
||||
49 46.58 142.42
|
||||
50 43.10 131.56
|
||||
51 41.01 28.58
|
||||
52 38.25 27.09
|
||||
53 39.56 32.52
|
||||
54 38.43 35.30
|
||||
55 39.45 37.02
|
||||
56 39.55 41.17
|
||||
57 37.55 40.14
|
||||
58 37.01 35.18
|
||||
59 36.12 37.10
|
||||
60 34.44 36.43
|
||||
61 33.30 36.18
|
||||
62 33.53 35.30
|
||||
63 31.57 35.56
|
||||
64 32.50 35.00
|
||||
65 32.04 34.46
|
||||
66 31.46 35.14
|
||||
67 24.28 39.36
|
||||
68 21.30 39.12
|
||||
69 21.27 39.49
|
||||
70 15.23 44.12
|
||||
71 14.48 42.57
|
||||
72 12.45 45.12
|
||||
73 14.32 49.08
|
||||
74 23.37 58.35
|
||||
75 25.18 55.18
|
||||
76 25.17 51.32
|
||||
77 26.13 50.35
|
||||
78 24.38 46.43
|
||||
79 29.20 47.59
|
||||
80 30.30 47.47
|
||||
81 33.21 44.25
|
||||
82 35.28 44.28
|
||||
83 36.20 43.08
|
||||
84 38.05 46.18
|
||||
85 37.16 49.36
|
||||
86 35.40 51.26
|
||||
87 34.19 47.04
|
||||
88 30.20 48.16
|
||||
89 32.40 51.38
|
||||
90 29.36 52.32
|
||||
91 30.17 57.05
|
||||
92 36.18 59.36
|
||||
93 34.20 62.12
|
||||
94 31.32 65.30
|
||||
95 34.31 69.12
|
||||
96 33.36 73.04
|
||||
97 31.35 74.18
|
||||
98 31.25 73.05
|
||||
99 30.11 71.29
|
||||
100 30.12 67.00
|
||||
101 27.42 68.52
|
||||
102 25.22 68.22
|
||||
103 24.52 67.03
|
||||
104 30.19 78.02
|
||||
105 28.40 77.13
|
||||
106 26.17 73.02
|
||||
107 26.55 75.49
|
||||
108 26.28 80.21
|
||||
109 25.20 83.00
|
||||
110 25.36 85.07
|
||||
111 22.32 88.22
|
||||
112 23.02 72.37
|
||||
113 21.09 79.06
|
||||
114 20.30 85.50
|
||||
115 18.58 72.50
|
||||
116 17.23 78.29
|
||||
117 17.42 83.18
|
||||
118 15.21 75.10
|
||||
119 12.59 77.35
|
||||
120 13.05 80.17
|
||||
121 10.49 78.41
|
||||
122 9.56 78.07
|
||||
123 6.56 79.51
|
||||
124 27.43 85.19
|
||||
125 27.28 89.39
|
||||
126 23.43 90.25
|
||||
127 22.20 91.50
|
||||
128 22.00 96.05
|
||||
129 16.47 96.10
|
||||
130 18.47 98.59
|
||||
131 19.52 102.08
|
||||
132 17.58 102.36
|
||||
133 21.02 105.51
|
||||
134 16.28 107.36
|
||||
135 16.04 108.13
|
||||
136 10.45 106.40
|
||||
137 11.33 104.55
|
||||
138 13.45 100.31
|
||||
139 5.25 100.20
|
||||
140 3.10 101.42
|
||||
141 1.17 103.51
|
||||
142 3.35 98.40
|
||||
143 -0.57 100.21
|
||||
144 -2.55 104.45
|
||||
145 -6.10 106.48
|
||||
146 -6.54 107.36
|
||||
147 -7.48 110.22
|
||||
148 -7.15 112.45
|
||||
149 -8.39 115.13
|
||||
150 -10.10 123.35
|
||||
151 -3.20 114.35
|
||||
152 1.33 110.20
|
||||
153 4.56 114.55
|
||||
154 -0.30 117.09
|
||||
155 -5.07 119.24
|
||||
156 1.29 124.51
|
||||
157 -3.43 128.12
|
||||
158 -5.40 132.45
|
||||
159 7.04 125.36
|
||||
160 10.18 123.54
|
||||
161 10.42 122.34
|
||||
162 14.35 121.00
|
||||
163 22.17 114.09
|
||||
164 22.38 120.17
|
||||
165 25.03 121.30
|
||||
166 29.40 91.09
|
||||
167 36.03 103.41
|
||||
168 34.15 108.52
|
||||
169 30.39 104.04
|
||||
170 29.39 106.34
|
||||
171 25.05 102.40
|
||||
172 23.06 113.16
|
||||
173 26.06 119.17
|
||||
174 30.36 114.17
|
||||
175 32.03 118.47
|
||||
176 31.14 121.28
|
||||
177 34.48 113.39
|
||||
178 36.06 120.19
|
||||
179 37.55 112.30
|
||||
180 39.08 117.12
|
||||
181 39.55 116.25
|
||||
182 38.53 121.35
|
||||
183 41.48 123.27
|
||||
184 45.45 126.41
|
||||
185 39.01 125.45
|
||||
186 37.33 126.58
|
||||
187 35.06 129.03
|
||||
188 43.03 141.21
|
||||
189 39.43 140.07
|
||||
190 38.15 140.53
|
||||
191 35.42 139.46
|
||||
192 35.10 136.55
|
||||
193 36.34 136.39
|
||||
194 35.00 135.45
|
||||
195 34.40 135.30
|
||||
196 34.24 132.27
|
||||
197 32.48 129.55
|
||||
198 31.36 130.33
|
||||
199 26.13 127.40
|
||||
200 13.28 144.47
|
||||
201 -2.32 140.42
|
||||
202 -4.12 152.12
|
||||
203 -9.30 147.10
|
||||
204 -12.28 130.50
|
||||
205 -31.56 115.50
|
||||
206 -34.55 138.35
|
||||
207 -37.49 144.58
|
||||
208 -42.53 147.19
|
||||
209 -33.52 151.13
|
||||
210 -27.28 153.02
|
||||
211 -19.16 146.48
|
||||
212 -23.42 133.53
|
||||
213 -45.52 170.30
|
||||
214 -43.32 172.38
|
||||
215 -41.18 174.47
|
||||
216 -36.52 174.46
|
||||
217 -21.08 -175.12
|
||||
218 -14.16 -170.42
|
||||
219 -18.08 178.25
|
||||
220 -22.16 166.27
|
||||
221 -9.26 159.57
|
||||
222 -0.32 166.55
|
||||
223 11.35 165.23
|
||||
224 21.19 -157.52
|
||||
225 1.52 -157.20
|
||||
226 -9.45 -139.00
|
||||
227 -17.32 -149.34
|
||||
228 -25.04 -130.06
|
||||
229 -27.07 -109.22
|
440
data/gr431
Normal file
440
data/gr431
Normal file
@ -0,0 +1,440 @@
|
||||
NAME: gr431
|
||||
TYPE: TSP
|
||||
COMMENT: Europe/Asia/Australia-Subproblem of 666-city TSP (Groetschel)
|
||||
DIMENSION: 431
|
||||
EDGE_WEIGHT_TYPE: GEO
|
||||
EDGE_WEIGHT_FORMAT: FUNCTION
|
||||
DISPLAY_DATA_TYPE: COORD_DISPLAY
|
||||
NODE_COORD_SECTION
|
||||
1 37.44 -25.40
|
||||
2 38.43 -9.08
|
||||
3 41.11 -8.36
|
||||
4 37.23 -5.59
|
||||
5 36.32 -6.18
|
||||
6 36.43 -4.25
|
||||
7 37.13 -3.41
|
||||
8 37.53 -4.46
|
||||
9 38.21 -0.29
|
||||
10 39.28 -0.22
|
||||
11 41.23 2.11
|
||||
12 41.38 -0.53
|
||||
13 40.24 -3.41
|
||||
14 41.39 -4.43
|
||||
15 43.15 -2.58
|
||||
16 43.22 -8.23
|
||||
17 38.54 1.26
|
||||
18 39.34 2.39
|
||||
19 42.30 1.31
|
||||
20 44.50 -0.34
|
||||
21 43.36 1.26
|
||||
22 43.18 5.24
|
||||
23 43.42 7.15
|
||||
24 43.42 7.23
|
||||
25 42.42 9.27
|
||||
26 45.50 1.16
|
||||
27 45.26 4.24
|
||||
28 45.45 4.51
|
||||
29 45.10 5.43
|
||||
30 48.24 -4.29
|
||||
31 48.05 -1.41
|
||||
32 47.13 -1.33
|
||||
33 47.23 0.41
|
||||
34 49.30 0.08
|
||||
35 48.52 2.20
|
||||
36 49.15 4.02
|
||||
37 47.19 5.01
|
||||
38 48.41 6.12
|
||||
39 48.35 7.45
|
||||
40 49.36 6.09
|
||||
41 50.38 5.34
|
||||
42 50.50 4.20
|
||||
43 50.38 3.04
|
||||
44 51.03 3.43
|
||||
45 51.13 4.25
|
||||
46 51.26 5.28
|
||||
47 51.55 4.28
|
||||
48 52.22 4.54
|
||||
49 52.05 5.08
|
||||
50 53.13 6.33
|
||||
51 50.23 -4.10
|
||||
52 50.43 -1.54
|
||||
53 50.50 -0.08
|
||||
54 51.29 -3.13
|
||||
55 51.27 -2.35
|
||||
56 51.30 -0.10
|
||||
57 52.30 -1.50
|
||||
58 53.25 -2.55
|
||||
59 53.30 -2.15
|
||||
60 53.23 -1.30
|
||||
61 53.50 -1.35
|
||||
62 54.59 -1.35
|
||||
63 55.57 -3.13
|
||||
64 55.53 -4.15
|
||||
65 56.28 -3.00
|
||||
66 57.10 -2.04
|
||||
67 60.09 -1.09
|
||||
68 62.01 -6.46
|
||||
69 51.54 -8.28
|
||||
70 52.40 -8.38
|
||||
71 53.20 -6.15
|
||||
72 54.35 -5.55
|
||||
73 55.00 -7.19
|
||||
74 64.09 -21.51
|
||||
75 64.11 -51.44
|
||||
76 76.34 -68.47
|
||||
77 70.40 23.42
|
||||
78 68.26 17.25
|
||||
79 65.01 25.28
|
||||
80 61.30 23.45
|
||||
81 60.27 22.17
|
||||
82 60.10 24.58
|
||||
83 63.25 10.25
|
||||
84 60.23 5.20
|
||||
85 58.58 5.45
|
||||
86 59.55 10.45
|
||||
87 57.43 11.58
|
||||
88 55.36 13.00
|
||||
89 58.25 15.37
|
||||
90 59.20 18.03
|
||||
91 57.38 18.18
|
||||
92 56.09 10.13
|
||||
93 55.24 10.23
|
||||
94 55.40 12.35
|
||||
95 53.04 8.49
|
||||
96 53.33 9.59
|
||||
97 54.20 10.08
|
||||
98 54.05 12.07
|
||||
99 51.57 7.37
|
||||
100 52.24 9.44
|
||||
101 52.07 11.38
|
||||
102 52.31 13.24
|
||||
103 50.47 6.05
|
||||
104 50.44 7.05
|
||||
105 50.56 6.59
|
||||
106 51.12 6.47
|
||||
107 51.17 7.17
|
||||
108 51.28 7.01
|
||||
109 51.28 7.13
|
||||
110 51.32 7.13
|
||||
111 51.31 7.28
|
||||
112 51.19 9.29
|
||||
113 50.58 11.01
|
||||
114 51.29 11.58
|
||||
115 51.19 12.20
|
||||
116 50.50 12.55
|
||||
117 51.03 13.44
|
||||
118 49.14 6.59
|
||||
119 50.07 8.40
|
||||
120 49.25 8.43
|
||||
121 49.48 9.56
|
||||
122 49.27 11.04
|
||||
123 49.03 8.24
|
||||
124 48.46 9.11
|
||||
125 49.01 12.06
|
||||
126 48.08 11.34
|
||||
127 46.12 6.09
|
||||
128 46.31 6.38
|
||||
129 46.57 7.26
|
||||
130 47.33 7.35
|
||||
131 47.23 8.32
|
||||
132 47.16 11.24
|
||||
133 47.48 13.02
|
||||
134 48.18 14.18
|
||||
135 48.13 16.20
|
||||
136 47.05 15.27
|
||||
137 45.03 7.40
|
||||
138 45.28 9.12
|
||||
139 45.27 11.00
|
||||
140 45.27 12.21
|
||||
141 45.40 13.46
|
||||
142 44.25 8.57
|
||||
143 44.29 11.20
|
||||
144 43.46 11.15
|
||||
145 43.55 12.28
|
||||
146 39.20 9.00
|
||||
147 41.54 12.29
|
||||
148 40.51 14.17
|
||||
149 41.27 15.34
|
||||
150 41.07 16.52
|
||||
151 40.28 17.15
|
||||
152 38.11 15.33
|
||||
153 37.30 15.06
|
||||
154 38.07 13.21
|
||||
155 35.54 14.31
|
||||
156 53.24 14.32
|
||||
157 54.23 18.40
|
||||
158 53.08 18.00
|
||||
159 52.25 16.55
|
||||
160 51.46 19.30
|
||||
161 52.15 21.00
|
||||
162 53.09 23.09
|
||||
163 51.06 17.00
|
||||
164 50.16 19.00
|
||||
165 50.03 19.58
|
||||
166 51.15 22.35
|
||||
167 49.45 13.23
|
||||
168 50.05 14.26
|
||||
169 49.50 18.17
|
||||
170 49.12 16.37
|
||||
171 48.09 17.07
|
||||
172 48.43 21.15
|
||||
173 47.30 19.05
|
||||
174 47.32 21.38
|
||||
175 46.05 18.13
|
||||
176 46.15 20.09
|
||||
177 45.45 21.13
|
||||
178 46.47 23.36
|
||||
179 47.10 27.35
|
||||
180 45.48 24.09
|
||||
181 45.39 25.37
|
||||
182 44.26 26.06
|
||||
183 44.11 28.39
|
||||
184 46.03 14.31
|
||||
185 45.20 14.27
|
||||
186 45.48 15.58
|
||||
187 43.31 16.27
|
||||
188 43.52 18.25
|
||||
189 44.50 20.30
|
||||
190 42.38 18.07
|
||||
191 41.59 21.26
|
||||
192 41.20 19.50
|
||||
193 42.41 23.19
|
||||
194 42.09 24.45
|
||||
195 43.13 27.55
|
||||
196 42.30 27.28
|
||||
197 39.36 19.56
|
||||
198 40.38 22.56
|
||||
199 38.15 21.44
|
||||
200 37.58 23.43
|
||||
201 35.20 25.09
|
||||
202 35.10 33.22
|
||||
203 68.58 33.05
|
||||
204 64.34 40.32
|
||||
205 59.55 30.15
|
||||
206 59.25 24.45
|
||||
207 56.57 24.06
|
||||
208 54.43 20.30
|
||||
209 54.41 25.19
|
||||
210 53.54 27.34
|
||||
211 49.50 24.00
|
||||
212 50.26 30.31
|
||||
213 46.28 30.44
|
||||
214 55.45 37.35
|
||||
215 56.20 44.00
|
||||
216 55.45 49.08
|
||||
217 53.12 50.09
|
||||
218 51.40 39.10
|
||||
219 50.00 36.15
|
||||
220 48.27 34.59
|
||||
221 44.36 33.32
|
||||
222 47.14 39.42
|
||||
223 48.44 44.25
|
||||
224 46.21 48.03
|
||||
225 41.43 44.49
|
||||
226 40.11 44.30
|
||||
227 40.23 49.51
|
||||
228 58.00 56.15
|
||||
229 56.51 60.36
|
||||
230 67.27 63.58
|
||||
231 69.20 88.06
|
||||
232 55.00 73.24
|
||||
233 55.02 82.55
|
||||
234 56.01 92.50
|
||||
235 49.50 73.10
|
||||
236 43.15 76.57
|
||||
237 41.20 69.18
|
||||
238 39.40 66.48
|
||||
239 38.35 68.48
|
||||
240 43.48 87.35
|
||||
241 52.16 104.20
|
||||
242 47.55 106.53
|
||||
243 52.03 113.30
|
||||
244 62.13 129.49
|
||||
245 64.45 177.29
|
||||
246 53.01 158.39
|
||||
247 59.34 150.48
|
||||
248 50.17 127.32
|
||||
249 50.35 137.02
|
||||
250 48.27 135.06
|
||||
251 46.58 142.42
|
||||
252 43.10 131.56
|
||||
253 41.01 28.58
|
||||
254 38.25 27.09
|
||||
255 39.56 32.52
|
||||
256 38.43 35.30
|
||||
257 39.45 37.02
|
||||
258 39.55 41.17
|
||||
259 37.55 40.14
|
||||
260 37.01 35.18
|
||||
261 36.12 37.10
|
||||
262 34.44 36.43
|
||||
263 33.30 36.18
|
||||
264 33.53 35.30
|
||||
265 31.57 35.56
|
||||
266 32.50 35.00
|
||||
267 32.04 34.46
|
||||
268 31.46 35.14
|
||||
269 24.28 39.36
|
||||
270 21.30 39.12
|
||||
271 21.27 39.49
|
||||
272 15.23 44.12
|
||||
273 14.48 42.57
|
||||
274 12.45 45.12
|
||||
275 14.32 49.08
|
||||
276 23.37 58.35
|
||||
277 25.18 55.18
|
||||
278 25.17 51.32
|
||||
279 26.13 50.35
|
||||
280 24.38 46.43
|
||||
281 29.20 47.59
|
||||
282 30.30 47.47
|
||||
283 33.21 44.25
|
||||
284 35.28 44.28
|
||||
285 36.20 43.08
|
||||
286 38.05 46.18
|
||||
287 37.16 49.36
|
||||
288 35.40 51.26
|
||||
289 34.19 47.04
|
||||
290 30.20 48.16
|
||||
291 32.40 51.38
|
||||
292 29.36 52.32
|
||||
293 30.17 57.05
|
||||
294 36.18 59.36
|
||||
295 34.20 62.12
|
||||
296 31.32 65.30
|
||||
297 34.31 69.12
|
||||
298 33.36 73.04
|
||||
299 31.35 74.18
|
||||
300 31.25 73.05
|
||||
301 30.11 71.29
|
||||
302 30.12 67.00
|
||||
303 27.42 68.52
|
||||
304 25.22 68.22
|
||||
305 24.52 67.03
|
||||
306 30.19 78.02
|
||||
307 28.40 77.13
|
||||
308 26.17 73.02
|
||||
309 26.55 75.49
|
||||
310 26.28 80.21
|
||||
311 25.20 83.00
|
||||
312 25.36 85.07
|
||||
313 22.32 88.22
|
||||
314 23.02 72.37
|
||||
315 21.09 79.06
|
||||
316 20.30 85.50
|
||||
317 18.58 72.50
|
||||
318 17.23 78.29
|
||||
319 17.42 83.18
|
||||
320 15.21 75.10
|
||||
321 12.59 77.35
|
||||
322 13.05 80.17
|
||||
323 10.49 78.41
|
||||
324 9.56 78.07
|
||||
325 6.56 79.51
|
||||
326 27.43 85.19
|
||||
327 27.28 89.39
|
||||
328 23.43 90.25
|
||||
329 22.20 91.50
|
||||
330 22.00 96.05
|
||||
331 16.47 96.10
|
||||
332 18.47 98.59
|
||||
333 19.52 102.08
|
||||
334 17.58 102.36
|
||||
335 21.02 105.51
|
||||
336 16.28 107.36
|
||||
337 16.04 108.13
|
||||
338 10.45 106.40
|
||||
339 11.33 104.55
|
||||
340 13.45 100.31
|
||||
341 5.25 100.20
|
||||
342 3.10 101.42
|
||||
343 1.17 103.51
|
||||
344 3.35 98.40
|
||||
345 -0.57 100.21
|
||||
346 -2.55 104.45
|
||||
347 -6.10 106.48
|
||||
348 -6.54 107.36
|
||||
349 -7.48 110.22
|
||||
350 -7.15 112.45
|
||||
351 -8.39 115.13
|
||||
352 -10.10 123.35
|
||||
353 -3.20 114.35
|
||||
354 1.33 110.20
|
||||
355 4.56 114.55
|
||||
356 -0.30 117.09
|
||||
357 -5.07 119.24
|
||||
358 1.29 124.51
|
||||
359 -3.43 128.12
|
||||
360 -5.40 132.45
|
||||
361 7.04 125.36
|
||||
362 10.18 123.54
|
||||
363 10.42 122.34
|
||||
364 14.35 121.00
|
||||
365 22.17 114.09
|
||||
366 22.38 120.17
|
||||
367 25.03 121.30
|
||||
368 29.40 91.09
|
||||
369 36.03 103.41
|
||||
370 34.15 108.52
|
||||
371 30.39 104.04
|
||||
372 29.39 106.34
|
||||
373 25.05 102.40
|
||||
374 23.06 113.16
|
||||
375 26.06 119.17
|
||||
376 30.36 114.17
|
||||
377 32.03 118.47
|
||||
378 31.14 121.28
|
||||
379 34.48 113.39
|
||||
380 36.06 120.19
|
||||
381 37.55 112.30
|
||||
382 39.08 117.12
|
||||
383 39.55 116.25
|
||||
384 38.53 121.35
|
||||
385 41.48 123.27
|
||||
386 45.45 126.41
|
||||
387 39.01 125.45
|
||||
388 37.33 126.58
|
||||
389 35.06 129.03
|
||||
390 43.03 141.21
|
||||
391 39.43 140.07
|
||||
392 38.15 140.53
|
||||
393 35.42 139.46
|
||||
394 35.10 136.55
|
||||
395 36.34 136.39
|
||||
396 35.00 135.45
|
||||
397 34.40 135.30
|
||||
398 34.24 132.27
|
||||
399 32.48 129.55
|
||||
400 31.36 130.33
|
||||
401 26.13 127.40
|
||||
402 13.28 144.47
|
||||
403 -2.32 140.42
|
||||
404 -4.12 152.12
|
||||
405 -9.30 147.10
|
||||
406 -12.28 130.50
|
||||
407 -31.56 115.50
|
||||
408 -34.55 138.35
|
||||
409 -37.49 144.58
|
||||
410 -42.53 147.19
|
||||
411 -33.52 151.13
|
||||
412 -27.28 153.02
|
||||
413 -19.16 146.48
|
||||
414 -23.42 133.53
|
||||
415 -45.52 170.30
|
||||
416 -43.32 172.38
|
||||
417 -41.18 174.47
|
||||
418 -36.52 174.46
|
||||
419 -21.08 -175.12
|
||||
420 -14.16 -170.42
|
||||
421 -18.08 178.25
|
||||
422 -22.16 166.27
|
||||
423 -9.26 159.57
|
||||
424 -0.32 166.55
|
||||
425 11.35 165.23
|
||||
426 21.19 -157.52
|
||||
427 1.52 -157.20
|
||||
428 -9.45 -139.00
|
||||
429 -17.32 -149.34
|
||||
430 -25.04 -130.06
|
||||
431 -27.07 -109.22
|
||||
EOF
|
1984
data/mu1979
Normal file
1984
data/mu1979
Normal file
File diff suppressed because it is too large
Load Diff
15
data/phd
Normal file
15
data/phd
Normal file
@ -0,0 +1,15 @@
|
||||
NAME: phd
|
||||
TYPE: TSP
|
||||
DIMENSION: 10
|
||||
EDGE_WEIGHT_TYPE: EUC_2D
|
||||
NODE_COORD_SECTION
|
||||
1 0 0
|
||||
2 1 1
|
||||
3 2 -.5
|
||||
4 3.5 1.5
|
||||
5 2.5 2
|
||||
6 3 2.5
|
||||
7 2 3
|
||||
8 .5 2.75
|
||||
9 .75 2.25
|
||||
10 -.5 1.25
|
199
data/qa194
Normal file
199
data/qa194
Normal file
@ -0,0 +1,199 @@
|
||||
NAME : qa194
|
||||
TYPE : TSP
|
||||
DIMENSION : 194
|
||||
EDGE_WEIGHT_TYPE : EUC_2D
|
||||
NODE_COORD_SECTION
|
||||
1 24748.3333 50840.0000
|
||||
2 24758.8889 51211.9444
|
||||
3 24827.2222 51394.7222
|
||||
4 24904.4444 51175.0000
|
||||
5 24996.1111 51548.8889
|
||||
6 25010.0000 51039.4444
|
||||
7 25030.8333 51275.2778
|
||||
8 25067.7778 51077.5000
|
||||
9 25100.0000 51516.6667
|
||||
10 25103.3333 51521.6667
|
||||
11 25121.9444 51218.3333
|
||||
12 25150.8333 51537.7778
|
||||
13 25158.3333 51163.6111
|
||||
14 25162.2222 51220.8333
|
||||
15 25167.7778 51606.9444
|
||||
16 25168.8889 51086.3889
|
||||
17 25173.8889 51269.4444
|
||||
18 25210.8333 51394.1667
|
||||
19 25211.3889 51619.1667
|
||||
20 25214.1667 50807.2222
|
||||
21 25214.4444 51378.8889
|
||||
22 25223.3333 51451.6667
|
||||
23 25224.1667 51174.4444
|
||||
24 25233.3333 51333.3333
|
||||
25 25234.1667 51203.0556
|
||||
26 25235.5556 51330.0000
|
||||
27 25235.5556 51495.5556
|
||||
28 25242.7778 51428.8889
|
||||
29 25243.0556 51452.5000
|
||||
30 25252.5000 51559.1667
|
||||
31 25253.8889 51535.2778
|
||||
32 25253.8889 51549.7222
|
||||
33 25256.9444 51398.8889
|
||||
34 25263.6111 51516.3889
|
||||
35 25265.8333 51545.2778
|
||||
36 25266.6667 50969.1667
|
||||
37 25266.6667 51483.3333
|
||||
38 25270.5556 51532.7778
|
||||
39 25270.8333 51505.8333
|
||||
40 25270.8333 51523.0556
|
||||
41 25275.8333 51533.6111
|
||||
42 25277.2222 51547.7778
|
||||
43 25278.3333 51525.5556
|
||||
44 25278.3333 51541.3889
|
||||
45 25279.1667 51445.5556
|
||||
46 25281.1111 51535.0000
|
||||
47 25281.3889 51512.5000
|
||||
48 25283.3333 51533.3333
|
||||
49 25283.6111 51546.6667
|
||||
50 25284.7222 51555.2778
|
||||
51 25286.1111 51504.1667
|
||||
52 25286.1111 51534.1667
|
||||
53 25286.6667 51533.3333
|
||||
54 25287.5000 51537.7778
|
||||
55 25288.0556 51546.6667
|
||||
56 25290.8333 51528.3333
|
||||
57 25291.9444 51424.4444
|
||||
58 25292.5000 51520.8333
|
||||
59 25298.6111 51001.6667
|
||||
60 25300.8333 51394.4444
|
||||
61 25306.9444 51507.7778
|
||||
62 25311.9444 51003.0556
|
||||
63 25313.8889 50883.3333
|
||||
64 25315.2778 51438.6111
|
||||
65 25316.6667 50766.6667
|
||||
66 25320.5556 51495.5556
|
||||
67 25322.5000 51507.7778
|
||||
68 25325.2778 51470.0000
|
||||
69 25326.6667 51350.2778
|
||||
70 25337.5000 51425.0000
|
||||
71 25339.1667 51173.3333
|
||||
72 25340.5556 51293.6111
|
||||
73 25341.9444 51507.5000
|
||||
74 25358.8889 51333.6111
|
||||
75 25363.6111 51281.1111
|
||||
76 25368.6111 51226.3889
|
||||
77 25374.4444 51436.6667
|
||||
78 25377.7778 51294.7222
|
||||
79 25396.9444 51422.5000
|
||||
80 25400.0000 51183.3333
|
||||
81 25400.0000 51425.0000
|
||||
82 25404.7222 51073.0556
|
||||
83 25416.9444 51403.8889
|
||||
84 25416.9444 51457.7778
|
||||
85 25419.4444 50793.6111
|
||||
86 25429.7222 50785.8333
|
||||
87 25433.3333 51220.0000
|
||||
88 25440.8333 51378.0556
|
||||
89 25444.4444 50958.3333
|
||||
90 25451.3889 50925.0000
|
||||
91 25459.1667 51316.6667
|
||||
92 25469.7222 51397.5000
|
||||
93 25478.0556 51362.5000
|
||||
94 25480.5556 50938.8889
|
||||
95 25483.3333 51383.3333
|
||||
96 25490.5556 51373.6111
|
||||
97 25492.2222 51400.2778
|
||||
98 25495.0000 50846.6667
|
||||
99 25495.0000 50965.2778
|
||||
100 25497.5000 51485.2778
|
||||
101 25500.8333 50980.5556
|
||||
102 25510.5556 51242.2222
|
||||
103 25531.9444 51304.4444
|
||||
104 25533.3333 50977.2222
|
||||
105 25538.8889 51408.3333
|
||||
106 25545.8333 51387.5000
|
||||
107 25549.7222 51431.9444
|
||||
108 25550.0000 51433.3333
|
||||
109 25560.2778 51158.6111
|
||||
110 25566.9444 51484.7222
|
||||
111 25567.5000 50958.8889
|
||||
112 25574.7222 51486.3889
|
||||
113 25585.5556 51151.3889
|
||||
114 25609.4444 51092.2222
|
||||
115 25610.2778 51475.2778
|
||||
116 25622.5000 51454.4444
|
||||
117 25645.8333 51450.0000
|
||||
118 25650.0000 51372.2222
|
||||
119 25666.9444 51174.4444
|
||||
120 25683.8889 51505.8333
|
||||
121 25686.3889 51468.8889
|
||||
122 25696.1111 51260.8333
|
||||
123 25700.8333 51584.7222
|
||||
124 25708.3333 51591.6667
|
||||
125 25716.6667 51050.0000
|
||||
126 25717.5000 51057.7778
|
||||
127 25723.0556 51004.1667
|
||||
128 25734.7222 51547.5000
|
||||
129 25751.1111 51449.1667
|
||||
130 25751.9444 50920.8333
|
||||
131 25758.3333 51395.8333
|
||||
132 25765.2778 51019.7222
|
||||
133 25772.2222 51483.3333
|
||||
134 25775.8333 51023.0556
|
||||
135 25779.1667 51449.7222
|
||||
136 25793.3333 51409.4444
|
||||
137 25808.3333 51060.5556
|
||||
138 25816.6667 51133.3333
|
||||
139 25823.6111 51152.5000
|
||||
140 25826.6667 51043.8889
|
||||
141 25829.7222 51245.2778
|
||||
142 25833.3333 51072.2222
|
||||
143 25839.1667 51465.2778
|
||||
144 25847.7778 51205.8333
|
||||
145 25850.0000 51033.3333
|
||||
146 25856.6667 51083.3333
|
||||
147 25857.5000 51298.8889
|
||||
148 25857.5000 51441.3889
|
||||
149 25866.6667 51066.6667
|
||||
150 25867.7778 51205.5556
|
||||
151 25871.9444 51354.7222
|
||||
152 25872.5000 51258.3333
|
||||
153 25880.8333 51221.3889
|
||||
154 25883.0556 51185.2778
|
||||
155 25888.0556 51386.3889
|
||||
156 25900.0000 51000.0000
|
||||
157 25904.1667 51201.6667
|
||||
158 25928.3333 51337.5000
|
||||
159 25937.5000 51313.3333
|
||||
160 25944.7222 51456.3889
|
||||
161 25950.0000 51066.6667
|
||||
162 25951.6667 51349.7222
|
||||
163 25957.7778 51075.2778
|
||||
164 25958.3333 51099.4444
|
||||
165 25966.6667 51283.3333
|
||||
166 25983.3333 51400.0000
|
||||
167 25983.6111 51328.0556
|
||||
168 26000.2778 51294.4444
|
||||
169 26008.6111 51083.6111
|
||||
170 26016.6667 51333.3333
|
||||
171 26021.6667 51366.9444
|
||||
172 26033.3333 51116.6667
|
||||
173 26033.3333 51166.6667
|
||||
174 26033.6111 51163.8889
|
||||
175 26033.6111 51200.2778
|
||||
176 26048.8889 51056.9444
|
||||
177 26050.0000 51250.0000
|
||||
178 26050.2778 51297.5000
|
||||
179 26050.5556 51135.8333
|
||||
180 26055.0000 51316.1111
|
||||
181 26067.2222 51258.6111
|
||||
182 26074.7222 51083.6111
|
||||
183 26076.6667 51166.9444
|
||||
184 26077.2222 51222.2222
|
||||
185 26078.0556 51361.6667
|
||||
186 26083.6111 51147.2222
|
||||
187 26099.7222 51161.1111
|
||||
188 26108.0556 51244.7222
|
||||
189 26116.6667 51216.6667
|
||||
190 26123.6111 51169.1667
|
||||
191 26123.6111 51222.7778
|
||||
192 26133.3333 51216.6667
|
||||
193 26133.3333 51300.0000
|
||||
194 26150.2778 51108.0556
|
936
data/zi929
Normal file
936
data/zi929
Normal file
@ -0,0 +1,936 @@
|
||||
NAME : zi929
|
||||
COMMENT : 929 locations in Zimbabwe
|
||||
COMMENT : Derived from National Imagery and Mapping Agency data
|
||||
TYPE : TSP
|
||||
DIMENSION : 929
|
||||
EDGE_WEIGHT_TYPE : EUC_2D
|
||||
NODE_COORD_SECTION
|
||||
1 15700.0000 30316.6667
|
||||
2 16033.3333 28850.0000
|
||||
3 16200.0000 31583.3333
|
||||
4 16233.3333 31533.3333
|
||||
5 16250.0000 31516.6667
|
||||
6 16300.0000 29250.0000
|
||||
7 16500.0000 29933.3333
|
||||
8 16516.6667 28800.0000
|
||||
9 16516.6667 29983.3333
|
||||
10 16516.6667 31183.3333
|
||||
11 16566.6667 31583.3333
|
||||
12 16666.6667 29766.6667
|
||||
13 16666.6667 30700.0000
|
||||
14 16700.0000 31966.6667
|
||||
15 16716.6667 30900.0000
|
||||
16 16716.6667 32766.6667
|
||||
17 16733.3333 29883.3333
|
||||
18 16733.3333 31783.3333
|
||||
19 16750.0000 30233.3333
|
||||
20 16783.3333 31583.3333
|
||||
21 16800.0000 31116.6667
|
||||
22 16816.6667 28350.0000
|
||||
23 16816.6667 29683.3333
|
||||
24 16850.0000 29416.6667
|
||||
25 16900.0000 29416.6667
|
||||
26 16900.0000 29750.0000
|
||||
27 16900.0000 30150.0000
|
||||
28 16916.6667 30700.0000
|
||||
29 16916.6667 31533.3333
|
||||
30 16933.3333 31716.6667
|
||||
31 16933.3333 32066.6667
|
||||
32 16950.0000 29300.0000
|
||||
33 16950.0000 30500.0000
|
||||
34 16950.0000 31333.3333
|
||||
35 16966.6667 32866.6667
|
||||
36 17016.6667 31450.0000
|
||||
37 17033.3333 30433.3333
|
||||
38 17033.3333 30850.0000
|
||||
39 17033.3333 30866.6667
|
||||
40 17066.6667 28800.0000
|
||||
41 17083.3333 28400.0000
|
||||
42 17100.0000 28400.0000
|
||||
43 17100.0000 32350.0000
|
||||
44 17133.3333 29200.0000
|
||||
45 17133.3333 30900.0000
|
||||
46 17150.0000 28116.6667
|
||||
47 17150.0000 30666.6667
|
||||
48 17150.0000 32383.3333
|
||||
49 17183.3333 28066.6667
|
||||
50 17216.6667 32716.6667
|
||||
51 17233.3333 31000.0000
|
||||
52 17266.6667 30033.3333
|
||||
53 17266.6667 31050.0000
|
||||
54 17266.6667 31066.6667
|
||||
55 17283.3333 31050.0000
|
||||
56 17283.3333 31066.6667
|
||||
57 17283.3333 32466.6667
|
||||
58 17283.3333 32616.6667
|
||||
59 17300.0000 31333.3333
|
||||
60 17316.6667 30516.6667
|
||||
61 17316.6667 31033.3333
|
||||
62 17316.6667 31566.6667
|
||||
63 17333.3333 28933.3333
|
||||
64 17333.3333 31033.3333
|
||||
65 17333.3333 32983.3333
|
||||
66 17350.0000 30233.3333
|
||||
67 17350.0000 31066.6667
|
||||
68 17366.6667 30200.0000
|
||||
69 17366.6667 30950.0000
|
||||
70 17366.6667 31033.3333
|
||||
71 17366.6667 31100.0000
|
||||
72 17366.6667 32983.3333
|
||||
73 17383.3333 30400.0000
|
||||
74 17383.3333 30950.0000
|
||||
75 17383.3333 31033.3333
|
||||
76 17400.0000 32216.6667
|
||||
77 17400.0000 32933.3333
|
||||
78 17416.6667 28433.3333
|
||||
79 17416.6667 30166.6667
|
||||
80 17433.3333 32983.3333
|
||||
81 17450.0000 28266.6667
|
||||
82 17466.6667 28050.0000
|
||||
83 17466.6667 30916.6667
|
||||
84 17483.3333 27883.3333
|
||||
85 17483.3333 27950.0000
|
||||
86 17483.3333 27983.3333
|
||||
87 17516.6667 30966.6667
|
||||
88 17533.3333 27900.0000
|
||||
89 17533.3333 30450.0000
|
||||
90 17550.0000 28600.0000
|
||||
91 17550.0000 31816.6667
|
||||
92 17600.0000 31133.3333
|
||||
93 17616.6667 27333.3333
|
||||
94 17616.6667 27716.6667
|
||||
95 17616.6667 32016.6667
|
||||
96 17633.3333 30950.0000
|
||||
97 17650.0000 30483.3333
|
||||
98 17650.0000 31783.3333
|
||||
99 17666.6667 30800.0000
|
||||
100 17683.3333 29016.6667
|
||||
101 17683.3333 31083.3333
|
||||
102 17683.3333 31566.6667
|
||||
103 17716.6667 30550.0000
|
||||
104 17733.0556 31048.0556
|
||||
105 17733.3333 31116.6667
|
||||
106 17733.3333 31133.3333
|
||||
107 17735.2778 30915.2778
|
||||
108 17735.5556 30955.2778
|
||||
109 17735.5556 31129.1667
|
||||
110 17741.1111 31136.1111
|
||||
111 17745.0000 31093.3333
|
||||
112 17745.5556 30931.3889
|
||||
113 17746.1111 30921.9444
|
||||
114 17748.3333 31026.9444
|
||||
115 17748.6111 31046.1111
|
||||
116 17749.1667 31091.6667
|
||||
117 17750.0000 30992.2222
|
||||
118 17750.2778 31096.6667
|
||||
119 17750.5556 31100.0000
|
||||
120 17752.5000 31051.6667
|
||||
121 17753.0556 31121.3889
|
||||
122 17753.6111 30936.6667
|
||||
123 17756.3889 31093.0556
|
||||
124 17756.6667 31041.9444
|
||||
125 17756.6667 31111.9444
|
||||
126 17756.9444 31074.1667
|
||||
127 17756.9444 31102.5000
|
||||
128 17757.2222 31082.2222
|
||||
129 17757.7778 30982.7778
|
||||
130 17758.8889 31010.5556
|
||||
131 17760.2778 31136.6667
|
||||
132 17766.6667 30166.6667
|
||||
133 17766.6667 30400.0000
|
||||
134 17766.9444 31113.3333
|
||||
135 17768.0556 31047.5000
|
||||
136 17768.3333 31053.6111
|
||||
137 17768.6111 31043.6111
|
||||
138 17769.1667 31030.5556
|
||||
139 17770.0000 30981.3889
|
||||
140 17771.6667 31036.9444
|
||||
141 17774.1667 31006.3889
|
||||
142 17775.0000 31031.1111
|
||||
143 17776.6667 31048.6111
|
||||
144 17776.6667 31142.7778
|
||||
145 17780.0000 31018.6111
|
||||
146 17780.5556 31101.9444
|
||||
147 17781.3889 31113.6111
|
||||
148 17781.9444 31152.2222
|
||||
149 17782.5000 31024.1667
|
||||
150 17782.5000 31041.6667
|
||||
151 17783.3333 30900.0000
|
||||
152 17783.3333 31016.6667
|
||||
153 17783.3333 31066.6667
|
||||
154 17783.3333 31316.6667
|
||||
155 17783.8889 31121.6667
|
||||
156 17785.0000 31001.9444
|
||||
157 17787.7778 31092.5000
|
||||
158 17789.4444 31009.1667
|
||||
159 17789.7222 31048.3333
|
||||
160 17791.3889 31118.0556
|
||||
161 17793.6111 31022.5000
|
||||
162 17793.6111 31140.2778
|
||||
163 17794.1667 31009.1667
|
||||
164 17796.3889 31030.5556
|
||||
165 17797.7778 30965.5556
|
||||
166 17798.0556 31141.1111
|
||||
167 17799.1667 30987.5000
|
||||
168 17801.6667 31030.8333
|
||||
169 17802.2222 31003.3333
|
||||
170 17804.7222 31044.1667
|
||||
171 17806.1111 30925.2778
|
||||
172 17806.6667 31014.1667
|
||||
173 17808.0556 31081.6667
|
||||
174 17808.6111 31099.4444
|
||||
175 17812.5000 31123.0556
|
||||
176 17814.4444 31024.7222
|
||||
177 17815.2778 31100.2778
|
||||
178 17816.6667 31016.6667
|
||||
179 17816.6667 32766.6667
|
||||
180 17818.3333 31093.3333
|
||||
181 17820.0000 31145.2778
|
||||
182 17820.8333 31078.0556
|
||||
183 17820.8333 31130.0000
|
||||
184 17825.2778 30983.0556
|
||||
185 17830.0000 31075.5556
|
||||
186 17830.2778 31122.7778
|
||||
187 17830.8333 31098.8889
|
||||
188 17833.0556 31133.3333
|
||||
189 17833.3333 31016.6667
|
||||
190 17833.3333 31050.0000
|
||||
191 17835.5556 31110.2778
|
||||
192 17838.3333 30915.8333
|
||||
193 17839.7222 31070.8333
|
||||
194 17841.3889 31115.5556
|
||||
195 17841.9444 31060.5556
|
||||
196 17843.8889 30979.1667
|
||||
197 17845.8333 31054.7222
|
||||
198 17846.3889 30945.5556
|
||||
199 17848.0556 31015.0000
|
||||
200 17848.8889 31128.8889
|
||||
201 17850.0000 28900.0000
|
||||
202 17850.0000 31033.3333
|
||||
203 17850.0000 31066.6667
|
||||
204 17850.0000 31183.3333
|
||||
205 17850.0000 31383.3333
|
||||
206 17850.2778 31070.5556
|
||||
207 17850.2778 31083.8889
|
||||
208 17850.5556 31051.3889
|
||||
209 17852.7778 31084.7222
|
||||
210 17855.2778 30967.2222
|
||||
211 17856.6667 30993.8889
|
||||
212 17857.2222 31095.2778
|
||||
213 17858.6111 30950.0000
|
||||
214 17859.1667 31023.0556
|
||||
215 17859.7222 31122.7778
|
||||
216 17860.0000 31060.8333
|
||||
217 17863.8889 31029.7222
|
||||
218 17864.4444 31056.6667
|
||||
219 17865.2778 30941.6667
|
||||
220 17865.8333 30905.2778
|
||||
221 17866.3889 30927.2222
|
||||
222 17866.6667 31066.6667
|
||||
223 17869.1667 31112.5000
|
||||
224 17869.4444 30987.7778
|
||||
225 17877.2222 31002.2222
|
||||
226 17878.3333 31090.8333
|
||||
227 17879.4444 31016.6667
|
||||
228 17879.4444 31124.4444
|
||||
229 17882.7778 31042.2222
|
||||
230 17883.3333 30700.0000
|
||||
231 17884.4444 31009.1667
|
||||
232 17884.7222 30920.8333
|
||||
233 17885.8333 30991.9444
|
||||
234 17891.3889 31116.6667
|
||||
235 17892.7778 31071.3889
|
||||
236 17893.6111 31019.7222
|
||||
237 17900.0000 27300.0000
|
||||
238 17900.0000 31250.0000
|
||||
239 17910.5556 30992.2222
|
||||
240 17912.7778 31011.1111
|
||||
241 17915.2778 31005.5556
|
||||
242 17916.6667 30983.3333
|
||||
243 17927.5000 31008.6111
|
||||
244 17932.5000 30929.7222
|
||||
245 17933.3333 25833.3333
|
||||
246 17933.6111 30974.4444
|
||||
247 17934.4444 31010.5556
|
||||
248 17936.1111 31002.5000
|
||||
249 17938.8889 30958.3333
|
||||
250 17944.1667 30977.5000
|
||||
251 17966.6667 27500.0000
|
||||
252 17966.6667 30433.3333
|
||||
253 17983.3333 31066.6667
|
||||
254 18000.0000 27566.6667
|
||||
255 18016.6667 27133.3333
|
||||
256 18016.6667 31100.0000
|
||||
257 18033.3333 30150.0000
|
||||
258 18033.3333 31100.0000
|
||||
259 18033.3333 31316.6667
|
||||
260 18066.6667 27833.3333
|
||||
261 18066.6667 29850.0000
|
||||
262 18083.3333 30450.0000
|
||||
263 18083.3333 31216.6667
|
||||
264 18083.3333 31333.3333
|
||||
265 18100.0000 29900.0000
|
||||
266 18100.0000 29933.3333
|
||||
267 18100.0000 30900.0000
|
||||
268 18100.0000 31166.6667
|
||||
269 18116.6667 27450.0000
|
||||
270 18116.6667 29850.0000
|
||||
271 18133.3333 29600.0000
|
||||
272 18133.3333 29916.6667
|
||||
273 18133.3333 30133.3333
|
||||
274 18133.3333 30150.0000
|
||||
275 18150.0000 28383.3333
|
||||
276 18150.0000 31850.0000
|
||||
277 18166.6667 31233.3333
|
||||
278 18166.6667 31683.3333
|
||||
279 18183.3333 30700.0000
|
||||
280 18183.3333 31400.0000
|
||||
281 18183.3333 31550.0000
|
||||
282 18200.0000 29916.6667
|
||||
283 18216.6667 27400.0000
|
||||
284 18216.6667 27950.0000
|
||||
285 18216.6667 28933.3333
|
||||
286 18216.6667 29800.0000
|
||||
287 18216.6667 30933.3333
|
||||
288 18216.6667 32750.0000
|
||||
289 18266.6667 30566.6667
|
||||
290 18266.6667 30866.6667
|
||||
291 18266.6667 31100.0000
|
||||
292 18283.3333 32050.0000
|
||||
293 18300.0000 27983.3333
|
||||
294 18300.0000 30216.6667
|
||||
295 18300.0000 30683.3333
|
||||
296 18300.0000 31366.6667
|
||||
297 18316.6667 27066.6667
|
||||
298 18316.6667 29983.3333
|
||||
299 18316.6667 30583.3333
|
||||
300 18316.6667 30600.0000
|
||||
301 18316.6667 31133.3333
|
||||
302 18316.6667 31200.0000
|
||||
303 18333.3333 30600.0000
|
||||
304 18350.0000 29883.3333
|
||||
305 18350.0000 29916.6667
|
||||
306 18366.6667 26483.3333
|
||||
307 18366.6667 30083.3333
|
||||
308 18366.6667 32600.0000
|
||||
309 18366.6667 32666.6667
|
||||
310 18383.3333 29866.6667
|
||||
311 18383.3333 30683.3333
|
||||
312 18383.3333 31350.0000
|
||||
313 18400.0000 31766.6667
|
||||
314 18416.6667 28016.6667
|
||||
315 18450.0000 29450.0000
|
||||
316 18450.0000 29816.6667
|
||||
317 18466.6667 30700.0000
|
||||
318 18466.6667 31516.6667
|
||||
319 18483.3333 29416.6667
|
||||
320 18516.6667 31400.0000
|
||||
321 18533.3333 30533.3333
|
||||
322 18533.3333 32116.6667
|
||||
323 18550.0000 32116.6667
|
||||
324 18566.6667 31050.0000
|
||||
325 18583.3333 26316.6667
|
||||
326 18600.0000 29833.3333
|
||||
327 18616.6667 26866.6667
|
||||
328 18616.6667 27166.6667
|
||||
329 18616.6667 31566.6667
|
||||
330 18650.0000 29783.3333
|
||||
331 18650.0000 32616.6667
|
||||
332 18666.6667 28683.3333
|
||||
333 18683.3333 32633.3333
|
||||
334 18716.6667 27550.0000
|
||||
335 18716.6667 30816.6667
|
||||
336 18716.6667 31983.3333
|
||||
337 18716.6667 32166.6667
|
||||
338 18733.3333 28816.6667
|
||||
339 18733.3333 32800.0000
|
||||
340 18766.6667 28500.0000
|
||||
341 18783.3333 28666.6667
|
||||
342 18800.0000 28333.3333
|
||||
343 18800.0000 28466.6667
|
||||
344 18816.6667 27166.6667
|
||||
345 18816.6667 28650.0000
|
||||
346 18866.6667 27433.3333
|
||||
347 18883.3333 27416.6667
|
||||
348 18883.3333 32683.3333
|
||||
349 18900.0000 27466.6667
|
||||
350 18900.0000 31283.3333
|
||||
351 18916.6667 29816.6667
|
||||
352 18916.6667 29833.3333
|
||||
353 18933.3333 27766.6667
|
||||
354 18933.3333 30050.0000
|
||||
355 18933.3333 32583.3333
|
||||
356 18950.0000 27516.6667
|
||||
357 18950.0000 30283.3333
|
||||
358 18966.6667 27416.6667
|
||||
359 18966.6667 32383.3333
|
||||
360 18966.6667 32666.6667
|
||||
361 18983.3333 29300.0000
|
||||
362 18983.3333 30100.0000
|
||||
363 18983.3333 32616.6667
|
||||
364 19000.0000 28900.0000
|
||||
365 19000.0000 31033.3333
|
||||
366 19000.0000 32583.3333
|
||||
367 19016.6667 28533.3333
|
||||
368 19016.6667 28550.0000
|
||||
369 19016.6667 29733.3333
|
||||
370 19016.6667 30900.0000
|
||||
371 19033.3333 28600.0000
|
||||
372 19033.3333 29783.3333
|
||||
373 19066.6667 31750.0000
|
||||
374 19083.3333 28716.6667
|
||||
375 19083.3333 31166.6667
|
||||
376 19100.0000 27966.6667
|
||||
377 19116.6667 27683.3333
|
||||
378 19133.3333 27533.3333
|
||||
379 19133.3333 27650.0000
|
||||
380 19150.0000 28666.6667
|
||||
381 19150.0000 29800.0000
|
||||
382 19166.6667 27516.6667
|
||||
383 19166.6667 27583.3333
|
||||
384 19166.6667 32616.6667
|
||||
385 19183.3333 27466.6667
|
||||
386 19183.3333 27516.6667
|
||||
387 19183.3333 27600.0000
|
||||
388 19183.3333 27683.3333
|
||||
389 19200.0000 27616.6667
|
||||
390 19200.0000 27666.6667
|
||||
391 19200.0000 29816.6667
|
||||
392 19216.6667 27483.3333
|
||||
393 19216.6667 27516.6667
|
||||
394 19216.6667 27533.3333
|
||||
395 19216.6667 27566.6667
|
||||
396 19216.6667 27700.0000
|
||||
397 19233.3333 27600.0000
|
||||
398 19233.3333 29250.0000
|
||||
399 19250.0000 27633.3333
|
||||
400 19250.0000 27716.6667
|
||||
401 19266.6667 27366.6667
|
||||
402 19266.6667 27400.0000
|
||||
403 19266.6667 27433.3333
|
||||
404 19266.6667 27516.6667
|
||||
405 19266.6667 27550.0000
|
||||
406 19266.6667 27600.0000
|
||||
407 19283.3333 27333.3333
|
||||
408 19283.3333 27450.0000
|
||||
409 19283.3333 27633.3333
|
||||
410 19283.3333 27650.0000
|
||||
411 19283.3333 27666.6667
|
||||
412 19283.3333 29616.6667
|
||||
413 19283.3333 30533.3333
|
||||
414 19300.0000 27416.6667
|
||||
415 19300.0000 27516.6667
|
||||
416 19300.0000 27533.3333
|
||||
417 19300.0000 27633.3333
|
||||
418 19316.6667 27333.3333
|
||||
419 19316.6667 27366.6667
|
||||
420 19316.6667 27683.3333
|
||||
421 19333.3333 27500.0000
|
||||
422 19333.3333 27533.3333
|
||||
423 19333.3333 27633.3333
|
||||
424 19333.3333 27650.0000
|
||||
425 19333.3333 30183.3333
|
||||
426 19333.3333 31433.3333
|
||||
427 19350.0000 27016.6667
|
||||
428 19350.0000 27383.3333
|
||||
429 19350.0000 27400.0000
|
||||
430 19350.0000 27600.0000
|
||||
431 19350.0000 27633.3333
|
||||
432 19350.0000 27650.0000
|
||||
433 19350.0000 28466.6667
|
||||
434 19366.6667 26983.3333
|
||||
435 19366.6667 27050.0000
|
||||
436 19366.6667 27433.3333
|
||||
437 19366.6667 29566.6667
|
||||
438 19366.6667 30016.6667
|
||||
439 19383.3333 26916.6667
|
||||
440 19383.3333 27016.6667
|
||||
441 19383.3333 27466.6667
|
||||
442 19383.3333 27633.3333
|
||||
443 19383.3333 29600.0000
|
||||
444 19400.0000 26966.6667
|
||||
445 19400.0000 27066.6667
|
||||
446 19400.0000 27083.3333
|
||||
447 19400.0000 27200.0000
|
||||
448 19400.0000 27283.3333
|
||||
449 19400.0000 27666.6667
|
||||
450 19400.0000 28400.0000
|
||||
451 19400.0000 28450.0000
|
||||
452 19416.6667 27033.3333
|
||||
453 19416.6667 27166.6667
|
||||
454 19416.6667 27333.3333
|
||||
455 19416.6667 27633.3333
|
||||
456 19416.6667 27716.6667
|
||||
457 19433.3333 27133.3333
|
||||
458 19433.3333 27233.3333
|
||||
459 19433.3333 27400.0000
|
||||
460 19433.3333 27500.0000
|
||||
461 19433.3333 27516.6667
|
||||
462 19433.3333 27550.0000
|
||||
463 19433.3333 27633.3333
|
||||
464 19433.3333 27700.0000
|
||||
465 19433.3333 28950.0000
|
||||
466 19433.3333 30833.3333
|
||||
467 19450.0000 27016.6667
|
||||
468 19450.0000 27066.6667
|
||||
469 19450.0000 27250.0000
|
||||
470 19450.0000 27283.3333
|
||||
471 19450.0000 27516.6667
|
||||
472 19450.0000 27700.0000
|
||||
473 19450.0000 29816.6667
|
||||
474 19466.6667 27033.3333
|
||||
475 19466.6667 27066.6667
|
||||
476 19466.6667 27150.0000
|
||||
477 19466.6667 27200.0000
|
||||
478 19466.6667 27316.6667
|
||||
479 19466.6667 27366.6667
|
||||
480 19466.6667 27466.6667
|
||||
481 19466.6667 27666.6667
|
||||
482 19466.6667 29750.0000
|
||||
483 19466.6667 29766.6667
|
||||
484 19466.6667 31216.6667
|
||||
485 19483.3333 27050.0000
|
||||
486 19483.3333 27183.3333
|
||||
487 19483.3333 27233.3333
|
||||
488 19483.3333 27283.3333
|
||||
489 19483.3333 27366.6667
|
||||
490 19483.3333 27433.3333
|
||||
491 19483.3333 27450.0000
|
||||
492 19483.3333 27550.0000
|
||||
493 19483.3333 27616.6667
|
||||
494 19483.3333 28566.6667
|
||||
495 19483.3333 30783.3333
|
||||
496 19500.0000 27066.6667
|
||||
497 19500.0000 27100.0000
|
||||
498 19500.0000 27400.0000
|
||||
499 19500.0000 27716.6667
|
||||
500 19500.0000 27733.3333
|
||||
501 19500.0000 28750.0000
|
||||
502 19500.0000 29750.0000
|
||||
503 19516.6667 27233.3333
|
||||
504 19516.6667 27483.3333
|
||||
505 19516.6667 27533.3333
|
||||
506 19516.6667 27650.0000
|
||||
507 19516.6667 27750.0000
|
||||
508 19516.6667 32550.0000
|
||||
509 19533.3333 26916.6667
|
||||
510 19533.3333 27083.3333
|
||||
511 19533.3333 27100.0000
|
||||
512 19533.3333 27133.3333
|
||||
513 19533.3333 27216.6667
|
||||
514 19533.3333 27283.3333
|
||||
515 19533.3333 29933.3333
|
||||
516 19550.0000 27050.0000
|
||||
517 19550.0000 27166.6667
|
||||
518 19550.0000 27416.6667
|
||||
519 19550.0000 27750.0000
|
||||
520 19550.0000 32666.6667
|
||||
521 19550.0000 32783.3333
|
||||
522 19566.6667 27033.3333
|
||||
523 19566.6667 27066.6667
|
||||
524 19566.6667 27133.3333
|
||||
525 19583.3333 27133.3333
|
||||
526 19583.3333 27466.6667
|
||||
527 19583.3333 27666.6667
|
||||
528 19583.3333 27733.3333
|
||||
529 19583.3333 28033.3333
|
||||
530 19583.3333 30750.0000
|
||||
531 19600.0000 27166.6667
|
||||
532 19600.0000 27566.6667
|
||||
533 19600.0000 27766.6667
|
||||
534 19600.0000 32800.0000
|
||||
535 19616.6667 27033.3333
|
||||
536 19616.6667 27116.6667
|
||||
537 19616.6667 27516.6667
|
||||
538 19633.3333 27066.6667
|
||||
539 19633.3333 27100.0000
|
||||
540 19633.3333 27183.3333
|
||||
541 19633.3333 27683.3333
|
||||
542 19633.3333 27716.6667
|
||||
543 19633.3333 30833.3333
|
||||
544 19650.0000 27050.0000
|
||||
545 19650.0000 27083.3333
|
||||
546 19650.0000 27150.0000
|
||||
547 19650.0000 27550.0000
|
||||
548 19650.0000 27650.0000
|
||||
549 19650.0000 31166.6667
|
||||
550 19650.0000 32466.6667
|
||||
551 19666.6667 26966.6667
|
||||
552 19666.6667 27133.3333
|
||||
553 19666.6667 27250.0000
|
||||
554 19666.6667 27333.3333
|
||||
555 19666.6667 27416.6667
|
||||
556 19666.6667 27566.6667
|
||||
557 19666.6667 27616.6667
|
||||
558 19666.6667 27700.0000
|
||||
559 19666.6667 30000.0000
|
||||
560 19683.3333 27016.6667
|
||||
561 19683.3333 27383.3333
|
||||
562 19683.3333 27433.3333
|
||||
563 19683.3333 28850.0000
|
||||
564 19700.0000 27033.3333
|
||||
565 19700.0000 27066.6667
|
||||
566 19700.0000 27083.3333
|
||||
567 19700.0000 27466.6667
|
||||
568 19700.0000 27500.0000
|
||||
569 19700.0000 27650.0000
|
||||
570 19700.0000 27683.3333
|
||||
571 19700.0000 29666.6667
|
||||
572 19716.6667 27583.3333
|
||||
573 19716.6667 27766.6667
|
||||
574 19716.6667 28800.0000
|
||||
575 19716.6667 29500.0000
|
||||
576 19716.6667 31833.3333
|
||||
577 19733.3333 27600.0000
|
||||
578 19733.3333 27716.6667
|
||||
579 19733.3333 30666.6667
|
||||
580 19750.0000 27766.6667
|
||||
581 19750.0000 27783.3333
|
||||
582 19766.6667 27216.6667
|
||||
583 19766.6667 27316.6667
|
||||
584 19766.6667 27400.0000
|
||||
585 19766.6667 27616.6667
|
||||
586 19766.6667 27750.0000
|
||||
587 19766.6667 27800.0000
|
||||
588 19766.6667 28766.6667
|
||||
589 19766.6667 32416.6667
|
||||
590 19783.3333 27683.3333
|
||||
591 19783.3333 27783.3333
|
||||
592 19783.3333 29200.0000
|
||||
593 19783.3333 29366.6667
|
||||
594 19800.0000 27616.6667
|
||||
595 19800.0000 27650.0000
|
||||
596 19800.0000 27833.3333
|
||||
597 19800.0000 28750.0000
|
||||
598 19800.0000 32866.6667
|
||||
599 19816.6667 27683.3333
|
||||
600 19833.3333 27216.6667
|
||||
601 19833.3333 27400.0000
|
||||
602 19833.3333 27466.6667
|
||||
603 19833.3333 27633.3333
|
||||
604 19833.3333 27783.3333
|
||||
605 19850.0000 27383.3333
|
||||
606 19850.0000 27416.6667
|
||||
607 19850.0000 27650.0000
|
||||
608 19850.0000 27716.6667
|
||||
609 19850.0000 27783.3333
|
||||
610 19850.0000 27866.6667
|
||||
611 19866.6667 28266.6667
|
||||
612 19883.3333 27616.6667
|
||||
613 19894.4444 30758.3333
|
||||
614 19911.1111 29691.6667
|
||||
615 19916.6667 27366.6667
|
||||
616 19916.6667 27783.3333
|
||||
617 19916.6667 30050.0000
|
||||
618 19933.3333 27233.3333
|
||||
619 19933.3333 27266.6667
|
||||
620 19933.3333 27650.0000
|
||||
621 19933.3333 27700.0000
|
||||
622 19936.1111 31636.1111
|
||||
623 19950.0000 27333.3333
|
||||
624 19966.6667 27400.0000
|
||||
625 19966.6667 27416.6667
|
||||
626 19966.6667 31433.3333
|
||||
627 19966.6667 32333.3333
|
||||
628 20000.0000 28933.3333
|
||||
629 20016.6667 28850.0000
|
||||
630 20016.6667 29266.6667
|
||||
631 20016.6667 30516.6667
|
||||
632 20016.6667 31466.6667
|
||||
633 20032.7778 29884.7222
|
||||
634 20033.3333 27766.6667
|
||||
635 20033.3333 27933.3333
|
||||
636 20050.0000 27766.6667
|
||||
637 20050.0000 30483.3333
|
||||
638 20050.0000 30800.0000
|
||||
639 20050.0000 31266.6667
|
||||
640 20075.0000 28585.2778
|
||||
641 20075.8333 28406.6667
|
||||
642 20077.7778 28429.4444
|
||||
643 20080.0000 28658.3333
|
||||
644 20081.1111 28568.8889
|
||||
645 20083.3333 28590.5556
|
||||
646 20083.3333 28783.3333
|
||||
647 20083.3333 30533.3333
|
||||
648 20083.3333 30816.6667
|
||||
649 20083.3333 30833.3333
|
||||
650 20083.3333 31616.6667
|
||||
651 20085.0000 28551.9444
|
||||
652 20090.5556 28582.2222
|
||||
653 20092.7778 28574.4444
|
||||
654 20093.0556 28553.8889
|
||||
655 20093.3333 28586.1111
|
||||
656 20093.6111 28597.7778
|
||||
657 20095.0000 28612.7778
|
||||
658 20096.1111 28622.7778
|
||||
659 20097.7778 28680.8333
|
||||
660 20098.6111 28611.6667
|
||||
661 20098.8889 28558.8889
|
||||
662 20100.0000 27483.3333
|
||||
663 20100.0000 27666.6667
|
||||
664 20100.0000 27950.0000
|
||||
665 20100.0000 28500.0000
|
||||
666 20100.0000 28550.0000
|
||||
667 20100.0000 28638.3333
|
||||
668 20100.2778 28596.3889
|
||||
669 20100.5556 28652.7778
|
||||
670 20100.8333 28610.2778
|
||||
671 20101.3889 28645.2778
|
||||
672 20101.9444 28578.0556
|
||||
673 20103.3333 28475.0000
|
||||
674 20103.3333 28606.6667
|
||||
675 20103.3333 28621.9444
|
||||
676 20104.1667 28517.5000
|
||||
677 20106.3889 28605.8333
|
||||
678 20106.3889 28652.7778
|
||||
679 20107.5000 28591.9444
|
||||
680 20108.3333 28498.8889
|
||||
681 20111.1111 28596.9444
|
||||
682 20113.6111 28604.7222
|
||||
683 20113.8889 28527.7778
|
||||
684 20113.8889 28685.5556
|
||||
685 20116.3889 28615.2778
|
||||
686 20116.6667 27650.0000
|
||||
687 20116.6667 27900.0000
|
||||
688 20116.6667 30366.6667
|
||||
689 20119.4444 28583.8889
|
||||
690 20119.4444 28589.4444
|
||||
691 20120.2778 28511.1111
|
||||
692 20121.6667 28528.6111
|
||||
693 20122.5000 28495.5556
|
||||
694 20123.0556 28602.7778
|
||||
695 20123.0556 28609.7222
|
||||
696 20125.2778 28543.8889
|
||||
697 20127.7778 28578.6111
|
||||
698 20128.3333 28631.1111
|
||||
699 20128.8889 28570.0000
|
||||
700 20131.1111 28603.0556
|
||||
701 20131.6667 28494.7222
|
||||
702 20131.6667 28591.1111
|
||||
703 20133.8889 28650.5556
|
||||
704 20135.5556 28568.8889
|
||||
705 20136.1111 28517.2222
|
||||
706 20136.1111 28532.5000
|
||||
707 20136.6667 28456.9444
|
||||
708 20136.9444 28505.8333
|
||||
709 20137.5000 28485.8333
|
||||
710 20138.0556 28552.5000
|
||||
711 20140.2778 28564.4444
|
||||
712 20141.1111 28600.0000
|
||||
713 20141.9444 28575.2778
|
||||
714 20142.2222 28622.7778
|
||||
715 20142.5000 28531.6667
|
||||
716 20143.3333 28616.1111
|
||||
717 20144.4444 28473.3333
|
||||
718 20145.0000 28540.8333
|
||||
719 20145.8333 28594.7222
|
||||
720 20146.9444 28492.2222
|
||||
721 20147.2222 28564.4444
|
||||
722 20148.3333 28521.1111
|
||||
723 20149.1667 28529.4444
|
||||
724 20149.1667 28737.2222
|
||||
725 20149.4444 28595.2778
|
||||
726 20150.0000 27300.0000
|
||||
727 20150.0000 27700.0000
|
||||
728 20150.0000 28583.3333
|
||||
729 20150.0000 28616.6667
|
||||
730 20150.0000 29533.3333
|
||||
731 20152.5000 28536.6667
|
||||
732 20152.5000 28584.7222
|
||||
733 20154.7222 28525.2778
|
||||
734 20155.5556 28553.8889
|
||||
735 20158.3333 28601.1111
|
||||
736 20159.1667 28560.0000
|
||||
737 20160.5556 28508.0556
|
||||
738 20161.3889 28610.0000
|
||||
739 20162.5000 28538.8889
|
||||
740 20162.7778 28568.6111
|
||||
741 20163.8889 28652.5000
|
||||
742 20164.1667 28525.0000
|
||||
743 20165.2778 28679.4444
|
||||
744 20166.6667 27600.0000
|
||||
745 20166.6667 31083.3333
|
||||
746 20166.6667 32783.3333
|
||||
747 20167.5000 28556.3889
|
||||
748 20168.3333 28671.3889
|
||||
749 20170.8333 28618.0556
|
||||
750 20171.6667 28571.3889
|
||||
751 20172.2222 28578.6111
|
||||
752 20172.7778 28542.7778
|
||||
753 20173.0556 28630.2778
|
||||
754 20174.7222 28662.7778
|
||||
755 20177.7778 30836.1111
|
||||
756 20178.8889 28534.1667
|
||||
757 20179.4444 28609.7222
|
||||
758 20180.8333 28649.1667
|
||||
759 20183.3333 28633.3333
|
||||
760 20183.3333 31333.3333
|
||||
761 20184.4444 28586.1111
|
||||
762 20185.0000 28516.9444
|
||||
763 20185.0000 28601.1111
|
||||
764 20185.2778 28495.0000
|
||||
765 20185.5556 28559.1667
|
||||
766 20185.8333 28735.5556
|
||||
767 20187.2222 28667.7778
|
||||
768 20187.7778 28593.8889
|
||||
769 20190.0000 28620.5556
|
||||
770 20191.6667 28568.3333
|
||||
771 20193.0556 28636.1111
|
||||
772 20194.4444 28581.6667
|
||||
773 20197.5000 28531.9444
|
||||
774 20198.0556 28558.6111
|
||||
775 20198.8889 28620.0000
|
||||
776 20199.1667 28600.0000
|
||||
777 20199.4444 28631.9444
|
||||
778 20200.0000 27766.6667
|
||||
779 20200.0000 28550.0000
|
||||
780 20200.0000 32616.6667
|
||||
781 20200.8333 28567.5000
|
||||
782 20201.6667 28534.4444
|
||||
783 20201.9444 28577.2222
|
||||
784 20204.1667 28714.7222
|
||||
785 20205.0000 28595.0000
|
||||
786 20206.3889 28581.9444
|
||||
787 20206.9444 28609.7222
|
||||
788 20208.6111 28721.3889
|
||||
789 20212.2222 28681.6667
|
||||
790 20214.1667 28558.3333
|
||||
791 20214.4444 28652.5000
|
||||
792 20214.7222 28595.2778
|
||||
793 20215.8333 28664.7222
|
||||
794 20216.6667 27283.3333
|
||||
795 20216.6667 27766.6667
|
||||
796 20216.6667 29300.0000
|
||||
797 20216.6667 31416.6667
|
||||
798 20217.5000 28615.5556
|
||||
799 20218.6111 28589.1667
|
||||
800 20220.0000 28578.6111
|
||||
801 20221.6667 28573.8889
|
||||
802 20222.2222 28583.6111
|
||||
803 20222.2222 28711.1111
|
||||
804 20224.4444 28702.5000
|
||||
805 20225.5556 28278.8889
|
||||
806 20227.7778 28638.0556
|
||||
807 20228.0556 28629.4444
|
||||
808 20228.0556 28659.4444
|
||||
809 20228.6111 28618.3333
|
||||
810 20229.4444 28611.1111
|
||||
811 20233.3333 27300.0000
|
||||
812 20233.3333 28916.6667
|
||||
813 20233.6111 28719.7222
|
||||
814 20233.6111 28746.6667
|
||||
815 20237.2222 28746.1111
|
||||
816 20240.0000 28641.9444
|
||||
817 20266.6667 30916.6667
|
||||
818 20280.5556 29884.7222
|
||||
819 20300.0000 28933.3333
|
||||
820 20300.0000 32616.6667
|
||||
821 20316.6667 30516.6667
|
||||
822 20316.6667 32650.0000
|
||||
823 20316.6667 32733.3333
|
||||
824 20333.3333 30033.3333
|
||||
825 20333.3333 32500.0000
|
||||
826 20350.0000 31450.0000
|
||||
827 20366.6667 28333.3333
|
||||
828 20366.6667 28983.3333
|
||||
829 20366.6667 32400.0000
|
||||
830 20366.6667 32600.0000
|
||||
831 20383.3333 28216.6667
|
||||
832 20383.3333 32250.0000
|
||||
833 20400.0000 28900.0000
|
||||
834 20400.0000 31450.0000
|
||||
835 20416.6667 28483.3333
|
||||
836 20416.6667 28600.0000
|
||||
837 20416.6667 32100.0000
|
||||
838 20419.4444 31963.8889
|
||||
839 20433.3333 29683.3333
|
||||
840 20433.3333 30733.3333
|
||||
841 20433.3333 32483.3333
|
||||
842 20450.0000 29050.0000
|
||||
843 20466.6667 31866.6667
|
||||
844 20483.3333 27816.6667
|
||||
845 20483.3333 29916.6667
|
||||
846 20516.3889 29055.5556
|
||||
847 20516.6667 29316.6667
|
||||
848 20533.3333 29283.3333
|
||||
849 20550.0000 30533.3333
|
||||
850 20550.0000 31316.6667
|
||||
851 20550.0000 32400.0000
|
||||
852 20566.6667 29333.3333
|
||||
853 20566.6667 30400.0000
|
||||
854 20600.0000 27850.0000
|
||||
855 20600.0000 28383.3333
|
||||
856 20602.7778 31397.2222
|
||||
857 20613.8889 31113.8889
|
||||
858 20616.6667 28400.0000
|
||||
859 20616.6667 30050.0000
|
||||
860 20649.1667 29151.3889
|
||||
861 20666.6667 32266.6667
|
||||
862 20683.3333 28416.6667
|
||||
863 20698.6111 31625.0000
|
||||
864 20700.0000 28066.6667
|
||||
865 20749.1667 29701.3889
|
||||
866 20800.0000 29533.3333
|
||||
867 20800.0000 30800.0000
|
||||
868 20800.0000 32233.3333
|
||||
869 20850.0000 30200.0000
|
||||
870 20899.4444 30786.1111
|
||||
871 20916.6667 28466.6667
|
||||
872 20916.6667 28950.0000
|
||||
873 20927.7778 29441.6667
|
||||
874 20933.3333 29000.0000
|
||||
875 20950.0000 31366.6667
|
||||
876 20966.6667 30266.6667
|
||||
877 20966.6667 31733.3333
|
||||
878 20983.3333 29033.3333
|
||||
879 21000.0000 29216.6667
|
||||
880 21016.6667 31533.3333
|
||||
881 21033.3333 31450.0000
|
||||
882 21050.0000 28450.0000
|
||||
883 21050.0000 31666.6667
|
||||
884 21066.6667 29366.6667
|
||||
885 21083.3333 27716.6667
|
||||
886 21150.0000 31283.3333
|
||||
887 21166.6667 31550.0000
|
||||
888 21200.0000 27850.0000
|
||||
889 21250.0000 30733.3333
|
||||
890 21383.3333 31016.6667
|
||||
891 21416.6667 28533.3333
|
||||
892 21416.6667 30733.3333
|
||||
893 21423.8889 30728.8889
|
||||
894 21433.3333 28855.5556
|
||||
895 21433.3333 29900.0000
|
||||
896 21433.3333 32033.3333
|
||||
897 21466.6667 31583.3333
|
||||
898 21500.0000 28083.3333
|
||||
899 21516.6667 28866.6667
|
||||
900 21516.6667 29533.3333
|
||||
901 21533.3333 31483.3333
|
||||
902 21583.3333 31250.0000
|
||||
903 21633.3333 32100.0000
|
||||
904 21650.0000 28933.3333
|
||||
905 21666.9444 29124.7222
|
||||
906 21683.3333 31316.6667
|
||||
907 21700.0000 29200.0000
|
||||
908 21733.3333 29866.6667
|
||||
909 21815.2778 31570.8333
|
||||
910 21850.0000 29350.0000
|
||||
911 21850.0000 29400.0000
|
||||
912 21916.6667 29200.0000
|
||||
913 21916.6667 29366.6667
|
||||
914 21917.2222 30027.2222
|
||||
915 21944.7222 31627.7778
|
||||
916 21966.6667 29366.6667
|
||||
917 21966.6667 29583.3333
|
||||
918 22016.6667 29366.6667
|
||||
919 22016.6667 30166.6667
|
||||
920 22066.6667 31416.6667
|
||||
921 22083.3333 30150.0000
|
||||
922 22083.3333 30650.0000
|
||||
923 22116.6667 30066.6667
|
||||
924 22133.3333 30666.6667
|
||||
925 22150.0000 30633.3333
|
||||
926 22200.0000 30350.0000
|
||||
927 22200.0000 30783.3333
|
||||
928 22216.6667 30000.0000
|
||||
929 22233.3333 30933.3333
|
42
examples/greedy.cpp
Normal file
42
examples/greedy.cpp
Normal file
@ -0,0 +1,42 @@
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
#include "muscles/rgreedy.h"
|
||||
|
||||
#include "tsp/problem.h"
|
||||
#include "tsp/solution.h"
|
||||
#include "tsp/tsp.h"
|
||||
|
||||
auto mainGreedy(tsp::Problem const& problem, std::size_t start) {
|
||||
std::mt19937 rng;
|
||||
auto greedy = RGreedy<tsp::Solution>{0};
|
||||
return greedy(problem, rng, start);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
tsp::Tsp tspData{"../data/phd"};
|
||||
tsp::Problem const& problem = tspData.points();
|
||||
tsp::Solution solution;
|
||||
|
||||
std::size_t start = 0;
|
||||
|
||||
if(argc > 1) {
|
||||
std::istringstream iss{argv[1]};
|
||||
iss >> start;
|
||||
}
|
||||
|
||||
solution = mainGreedy(problem, start);
|
||||
|
||||
std::cout << "distance: " << solution.value() << std::endl;
|
||||
|
||||
// save
|
||||
{
|
||||
std::ofstream ofs{"solution"};
|
||||
ofs << solution;
|
||||
}
|
||||
{
|
||||
std::ofstream ofs{"solution.ids"};
|
||||
solution.printIndices(ofs);
|
||||
}
|
||||
}
|
10
inc/alsk/alsk.h
Normal file
10
inc/alsk/alsk.h
Normal file
@ -0,0 +1,10 @@
|
||||
#ifndef ALSK_ALSK_H
|
||||
#define ALSK_ALSK_H
|
||||
|
||||
#include "context/context.h"
|
||||
#include "edsl/edsl.h"
|
||||
#include "executor/executor.h"
|
||||
#include "impl/impl.h"
|
||||
#include "skeleton/skeleton.h"
|
||||
|
||||
#endif
|
90
inc/alsk/context/context.h
Normal file
90
inc/alsk/context/context.h
Normal file
@ -0,0 +1,90 @@
|
||||
#ifndef ALSK_ALSK_CONTEXT_CONTEXT_H
|
||||
#define ALSK_ALSK_CONTEXT_CONTEXT_H
|
||||
|
||||
#include <functional>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
#include <random>
|
||||
|
||||
#include "../skeleton/link/args/placeholders.h"
|
||||
|
||||
namespace alsk {
|
||||
|
||||
template<typename RNG>
|
||||
class Context {
|
||||
public:
|
||||
using Id = std::size_t;
|
||||
|
||||
using Args = std::tuple<Id, RNG&>;
|
||||
|
||||
using Seed = decltype(+RNG::default_seed);
|
||||
|
||||
private:
|
||||
Id _idCount;
|
||||
|
||||
std::vector<RNG> _rng;
|
||||
std::vector<Args> _args;
|
||||
|
||||
public:
|
||||
Seed seed;
|
||||
|
||||
public:
|
||||
constexpr Context(): _idCount{0}, seed{RNG::default_seed} {}
|
||||
|
||||
void setup(Id idCount = 30) {
|
||||
if(idCount <= _idCount) return;
|
||||
Id baseId = _idCount;
|
||||
_idCount = idCount;
|
||||
|
||||
RNG seeder{seed};
|
||||
|
||||
_rng.reserve(idCount);
|
||||
for(Id id = baseId; id < idCount; ++id)
|
||||
_rng.emplace_back(seeder());
|
||||
|
||||
_args.reserve(idCount);
|
||||
for(Id id = baseId; id < idCount; ++id)
|
||||
_args.emplace_back(id, std::ref(_rng[id]));
|
||||
}
|
||||
|
||||
void reset() {
|
||||
RNG seeder{seed};
|
||||
|
||||
_rng.clear();
|
||||
for(Id id = 0; id < _idCount; ++id)
|
||||
_rng.emplace_back(seeder());
|
||||
|
||||
_args.clear();
|
||||
for(Id id = 0; id < _idCount; ++id)
|
||||
_args.emplace_back(id, std::ref(_rng[id]));
|
||||
}
|
||||
|
||||
constexpr Id maxId() const noexcept { return _idCount; }
|
||||
|
||||
Args& args(Id const& id) { return _args[id]; }
|
||||
|
||||
~Context() noexcept {}
|
||||
};
|
||||
|
||||
using DefaultContext = Context<std::mt19937>;
|
||||
|
||||
namespace arg {
|
||||
|
||||
/**
|
||||
* CtxId
|
||||
* to get own's context identifier
|
||||
*/
|
||||
using CtxId = C<0>;
|
||||
|
||||
/**
|
||||
* RNG
|
||||
* for random number generator
|
||||
*/
|
||||
using RNG = C<1>;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
19
inc/alsk/edsl/edsl.h
Normal file
19
inc/alsk/edsl/edsl.h
Normal file
@ -0,0 +1,19 @@
|
||||
#ifndef ALSK_ALSK_EDSL_EDSL_H
|
||||
#define ALSK_ALSK_EDSL_EDSL_H
|
||||
|
||||
#include "implement.h"
|
||||
#include "link.h"
|
||||
#include "op/op.h"
|
||||
|
||||
namespace alsk {
|
||||
namespace edsl {
|
||||
|
||||
template<typename Expression, std::enable_if_t<isOperand<std::decay_t<Expression>>>* = nullptr>
|
||||
constexpr decltype(auto) seq(Expression&& expression) {
|
||||
return &std::forward<Expression>(expression);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
50
inc/alsk/edsl/implement.h
Normal file
50
inc/alsk/edsl/implement.h
Normal file
@ -0,0 +1,50 @@
|
||||
#ifndef ALSK_ALSK_EDSL_IMPL_H
|
||||
#define ALSK_ALSK_EDSL_IMPL_H
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "../executor/traits.h"
|
||||
#include "../skeleton/utility.h"
|
||||
#include "../impl/impl.h"
|
||||
|
||||
#include "op/impl/serial.h"
|
||||
#include "op/traits.h"
|
||||
#include "link.h"
|
||||
|
||||
namespace alsk {
|
||||
namespace edsl {
|
||||
|
||||
template<typename Expression>
|
||||
constexpr auto getSkeleton(Expression) -> BuildSkeletonT<typename Expression::Struct, typename Expression::Links>;
|
||||
|
||||
template<
|
||||
template<typename> class Executor, typename Context = DefaultContext,
|
||||
typename Expression,
|
||||
std::enable_if_t<isBranch<std::decay_t<Expression>>>* = nullptr
|
||||
>
|
||||
constexpr auto implement(Expression&& expression) {
|
||||
using Skeleton = decltype(getSkeleton(expression));
|
||||
|
||||
auto f = alsk::implement<Executor, Skeleton, Context>();
|
||||
std::forward<Expression>(expression).setup(f.skeleton);
|
||||
return f;
|
||||
}
|
||||
|
||||
template<
|
||||
template<typename> class Executor, typename Context = DefaultContext,
|
||||
typename Expression,
|
||||
std::enable_if_t<isLeaf<std::decay_t<Expression>>>* = nullptr
|
||||
>
|
||||
constexpr auto implement(Expression&& expression) {
|
||||
using Signature = typename std::decay_t<Expression>::Signature;
|
||||
using FixedSignatures = AutoLinkSerial<Signature>;
|
||||
auto linkedExpression = link<typename FixedSignatures::in>(std::forward<Expression>(expression));
|
||||
|
||||
using LinkedExpression = std::decay_t<decltype(linkedExpression)>;
|
||||
return implement<Executor, Context>(Serial<typename FixedSignatures::out, LinkedExpression>{std::move(linkedExpression)});
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
34
inc/alsk/edsl/link.h
Normal file
34
inc/alsk/edsl/link.h
Normal file
@ -0,0 +1,34 @@
|
||||
#ifndef ALSK_ALSK_EDSL_LINK_H
|
||||
#define ALSK_ALSK_EDSL_LINK_H
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "op/op.h"
|
||||
|
||||
namespace alsk {
|
||||
namespace edsl {
|
||||
|
||||
template<typename Signature, typename Expression>
|
||||
constexpr decltype(auto) link(Expression&& expression) {
|
||||
return std::forward<Expression>(expression).template link<Signature>();
|
||||
}
|
||||
|
||||
template<typename Signature, typename... Expressions, std::enable_if_t<(sizeof...(Expressions) > 1)>* = nullptr>
|
||||
constexpr decltype(auto) link(Expressions&&... expressions) {
|
||||
return link<Signature>(serial(std::forward<Expressions>(expressions)...));
|
||||
}
|
||||
|
||||
template<typename Signature, typename Type, std::enable_if_t<not isOperand<Type>>* = nullptr>
|
||||
constexpr decltype(auto) link() {
|
||||
return link<Signature>(makeOperand<Type>());
|
||||
}
|
||||
|
||||
template<typename Signature, typename Type, std::enable_if_t<isOperand<Type>>* = nullptr>
|
||||
constexpr decltype(auto) link() {
|
||||
return link<Signature, Type>();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
85
inc/alsk/edsl/op/impl/farm.h
Normal file
85
inc/alsk/edsl/op/impl/farm.h
Normal file
@ -0,0 +1,85 @@
|
||||
#ifndef ALSK_ALSK_EDSL_OP_IMPL_FARM_H
|
||||
#define ALSK_ALSK_EDSL_OP_IMPL_FARM_H
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "../traits.h"
|
||||
#include "../../../skeleton/bone/farm.h"
|
||||
#include "../../../skeleton/struct/struct.h"
|
||||
#include "../../../skeleton/link/link.h"
|
||||
|
||||
namespace alsk {
|
||||
namespace edsl {
|
||||
|
||||
template<typename, typename, typename> struct FarmSel;
|
||||
|
||||
template<typename Signature_, typename Task>
|
||||
struct Farm: OperandBase {
|
||||
Task task;
|
||||
unsigned int n;
|
||||
|
||||
constexpr Farm(Task task, unsigned int n)
|
||||
noexcept(noexcept(Task{std::move(task)})):
|
||||
task{std::move(task)}, n{n} {}
|
||||
|
||||
template<typename S>
|
||||
constexpr Farm(Farm<S, Task> const& o)
|
||||
noexcept(noexcept(Task{o.task})):
|
||||
task{o.task}, n{o.n} {}
|
||||
|
||||
template<typename S>
|
||||
constexpr Farm(Farm<S, Task>&& o)
|
||||
noexcept(noexcept(Task{std::move(o.task)})):
|
||||
task{std::move(o.task)}, n{std::move(o.n)} {}
|
||||
|
||||
using Signature = Signature_;
|
||||
|
||||
using Struct = S<alsk::Farm, typename Task::Struct>;
|
||||
using Links = L<alsk::Farm, Signature, typename Task::Links>;
|
||||
|
||||
template<typename S>
|
||||
constexpr void setup(S& skeleton) const {
|
||||
skeleton.n = n;
|
||||
setupFor(task, skeleton.task);
|
||||
}
|
||||
|
||||
template<typename Signature>
|
||||
constexpr auto link() const&& {
|
||||
return Farm<Signature, Task>{std::move(*this)};
|
||||
}
|
||||
|
||||
template<typename Signature>
|
||||
constexpr auto link() const& {
|
||||
return Farm<Signature, Task>{*this};
|
||||
}
|
||||
|
||||
template<typename Rhs, std::enable_if_t<isOperand<Rhs>>* = nullptr>
|
||||
constexpr auto select(Rhs const& rhs) {
|
||||
return FarmSel<GetReturnType<Rhs>(), Task, Rhs>{task, rhs, n};
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Signature = void(), typename Task, std::enable_if_t<isOperand<Task>>* = nullptr>
|
||||
constexpr auto farm(Task const& task, unsigned int n = 0) {
|
||||
return Farm<Signature, Task>{task, n};
|
||||
}
|
||||
|
||||
template<typename Rhs, std::enable_if_t<isOperand<Rhs>>* = nullptr>
|
||||
constexpr auto operator*(Rhs const& rhs) {
|
||||
return Farm<void(), Rhs>{rhs, 0};
|
||||
}
|
||||
|
||||
template<typename Rhs, std::enable_if_t<isOperand<Rhs>>* = nullptr>
|
||||
constexpr auto operator*(unsigned int n, Rhs const& rhs) {
|
||||
return Farm<void(), Rhs>{rhs, n};
|
||||
}
|
||||
|
||||
template<typename Lhs, std::enable_if_t<isOperand<Lhs>>* = nullptr>
|
||||
constexpr auto operator*(Lhs const& lhs, unsigned int n) {
|
||||
return Farm<void(), Lhs>{lhs, n};
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
70
inc/alsk/edsl/op/impl/farmsel.h
Normal file
70
inc/alsk/edsl/op/impl/farmsel.h
Normal file
@ -0,0 +1,70 @@
|
||||
#ifndef ALSK_ALSK_EDSL_OP_IMPL_FARMSEL_H
|
||||
#define ALSK_ALSK_EDSL_OP_IMPL_FARMSEL_H
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "../traits.h"
|
||||
#include "../../../skeleton/bone/farmsel.h"
|
||||
#include "../../../skeleton/struct/struct.h"
|
||||
#include "../../../skeleton/link/link.h"
|
||||
|
||||
namespace alsk {
|
||||
namespace edsl {
|
||||
|
||||
template<typename, typename> struct Farm;
|
||||
|
||||
template<typename Signature_, typename Task, typename Select>
|
||||
struct FarmSel: OperandBase {
|
||||
Task task;
|
||||
Select select;
|
||||
unsigned int n;
|
||||
|
||||
constexpr FarmSel(Task task, Select select, unsigned int n)
|
||||
noexcept(noexcept(Task{std::move(task)}) and noexcept(Select{std::move(select)})):
|
||||
task{std::move(task)}, select{std::move(select)}, n{n}
|
||||
{}
|
||||
|
||||
template<typename S>
|
||||
constexpr FarmSel(FarmSel<S, Task, Select> const& o)
|
||||
noexcept(noexcept(Task{o.task}) and noexcept(Select{o.select})):
|
||||
task{o.task}, select{o.select}, n{o.n}
|
||||
{}
|
||||
|
||||
template<typename S>
|
||||
constexpr FarmSel(FarmSel<S, Task, Select>&& o)
|
||||
noexcept(noexcept(Task{std::move(o.task)}) and noexcept(Select{std::move(o.select)})):
|
||||
task{std::move(o.task)}, select{std::move(o.select)}, n{std::move(o.n)}
|
||||
{}
|
||||
|
||||
using Signature = Signature_;
|
||||
|
||||
using Struct = S<alsk::FarmSel, typename Task::Struct, typename Select::Struct>;
|
||||
using Links = L<alsk::FarmSel, Signature, typename Task::Links, typename Select::Links>;
|
||||
|
||||
template<typename S>
|
||||
constexpr void setup(S& skeleton) const {
|
||||
skeleton.n = n;
|
||||
setupFor(task, skeleton.task);
|
||||
setupFor(select, skeleton.select);
|
||||
}
|
||||
|
||||
template<typename Signature>
|
||||
constexpr auto link() const&& {
|
||||
return FarmSel<Signature, Task, Select>{std::move(*this)};
|
||||
}
|
||||
|
||||
template<typename Signature>
|
||||
constexpr auto link() const& {
|
||||
return FarmSel<Signature, Task, Select>{*this};
|
||||
}
|
||||
};
|
||||
|
||||
template<typename FR, typename... FArgs, typename Task, typename Rhs, std::enable_if_t<isOperand<Rhs>>* = nullptr>
|
||||
constexpr auto operator->*(Farm<FR(FArgs...), Task> const& farm, Rhs const& rhs) {
|
||||
return FarmSel<GetReturnType<Rhs>(FArgs...), Task, Rhs>{farm.task, rhs, farm.n};
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
99
inc/alsk/edsl/op/impl/itersel.h
Normal file
99
inc/alsk/edsl/op/impl/itersel.h
Normal file
@ -0,0 +1,99 @@
|
||||
#ifndef ALSK_ALSK_EDSL_OP_IMPL_ITERSEL_H
|
||||
#define ALSK_ALSK_EDSL_OP_IMPL_ITERSEL_H
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "../traits.h"
|
||||
#include "../../../skeleton/bone/itersel.h"
|
||||
#include "../../../skeleton/struct/struct.h"
|
||||
#include "../../../skeleton/link/link.h"
|
||||
|
||||
namespace alsk {
|
||||
namespace edsl {
|
||||
|
||||
template<typename, typename> struct Loop;
|
||||
template<typename, typename, typename> struct FarmSel;
|
||||
|
||||
template<typename Signature_, typename Task, typename Select>
|
||||
struct IterSel: OperandBase {
|
||||
Task task;
|
||||
Select select;
|
||||
unsigned int n;
|
||||
|
||||
constexpr IterSel(Task task, Select select, unsigned int n)
|
||||
noexcept(noexcept(Task{std::move(task)}) and noexcept(Select{std::move(select)})):
|
||||
task{std::move(task)}, select{std::move(select)}, n{n}
|
||||
{}
|
||||
|
||||
template<typename S>
|
||||
constexpr IterSel(IterSel<S, Task, Select> const& o)
|
||||
noexcept(noexcept(Task{o.task}) and noexcept(Select{o.select})):
|
||||
task{o.task}, select{o.select}, n{o.n}
|
||||
{}
|
||||
|
||||
template<typename S>
|
||||
constexpr IterSel(IterSel<S, Task, Select>&& o)
|
||||
noexcept(noexcept(Task{std::move(o.task)}) and noexcept(Select{std::move(o.select)})):
|
||||
task{std::move(o.task)}, select{std::move(o.select)}, n{std::move(o.n)}
|
||||
{}
|
||||
|
||||
using Signature = Signature_;
|
||||
|
||||
using Struct = S<alsk::IterSel, typename Task::Struct, typename Select::Struct>;
|
||||
using Links = L<alsk::IterSel, Signature, typename Task::Links, typename Select::Links>;
|
||||
|
||||
template<typename S>
|
||||
constexpr void setup(S& skeleton) const {
|
||||
skeleton.n = n;
|
||||
setupFor(task, skeleton.task);
|
||||
setupFor(select, skeleton.select);
|
||||
}
|
||||
|
||||
template<typename Signature>
|
||||
constexpr auto link() const&& {
|
||||
return IterSel<Signature, Task, Select>{std::move(*this)};
|
||||
}
|
||||
|
||||
template<typename Signature>
|
||||
constexpr auto link() const& {
|
||||
return IterSel<Signature, Task, Select>{*this};
|
||||
}
|
||||
};
|
||||
|
||||
namespace impl {
|
||||
|
||||
template<typename, typename> struct Iter;
|
||||
|
||||
template<typename Task, typename R, typename... Args>
|
||||
struct Iter<Task, R(Args...)> {
|
||||
Task const& task;
|
||||
unsigned int n;
|
||||
|
||||
template<typename Select, std::enable_if_t<isOperand<Select>>* = nullptr>
|
||||
constexpr auto select(Select const& select) {
|
||||
using Signature = GetReturnType<Select>(Args...);
|
||||
return alsk::edsl::IterSel<Signature, Task, Select>{task, select, n};
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
template<typename Signature = void(), typename Task, std::enable_if_t<isOperand<Task>>* = nullptr>
|
||||
constexpr auto iter(Task const& task, unsigned int n = 0) {
|
||||
return impl::Iter<Task, Signature>{task, n};
|
||||
}
|
||||
|
||||
template<typename Signature, typename Task, typename Select>
|
||||
constexpr auto operator&(FarmSel<Signature, Task, Select> const& farmsel) {
|
||||
return IterSel<Signature, Task, Select>{farmsel.task, farmsel.select, farmsel.n};
|
||||
}
|
||||
|
||||
template<typename LR, typename... LArgs, typename Task, typename Rhs, std::enable_if_t<isOperand<Rhs>>* = nullptr>
|
||||
constexpr auto operator->*(Loop<LR(LArgs...), Task> const& loop, Rhs const& rhs) {
|
||||
return IterSel<GetReturnType<Rhs>(LArgs...), Task, Rhs>{loop.task, rhs, loop.n};
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
73
inc/alsk/edsl/op/impl/loop.h
Normal file
73
inc/alsk/edsl/op/impl/loop.h
Normal file
@ -0,0 +1,73 @@
|
||||
#ifndef ALSK_ALSK_EDSL_OP_IMPL_LOOP_H
|
||||
#define ALSK_ALSK_EDSL_OP_IMPL_LOOP_H
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "../traits.h"
|
||||
#include "../../../skeleton/bone/loop.h"
|
||||
#include "../../../skeleton/struct/struct.h"
|
||||
#include "../../../skeleton/link/link.h"
|
||||
|
||||
namespace alsk {
|
||||
namespace edsl {
|
||||
|
||||
template<typename, typename> struct Farm;
|
||||
|
||||
template<typename Signature_, typename Task>
|
||||
struct Loop: OperandBase {
|
||||
Task task;
|
||||
unsigned int n;
|
||||
|
||||
constexpr Loop(Task task, unsigned int n)
|
||||
noexcept(noexcept(Task{std::move(task)})):
|
||||
task{std::move(task)}, n{n}
|
||||
{}
|
||||
|
||||
template<typename S>
|
||||
constexpr Loop(Loop<S, Task> const& o)
|
||||
noexcept(noexcept(Task{o.task})):
|
||||
task{o.task}, n{o.n}
|
||||
{}
|
||||
|
||||
template<typename S>
|
||||
constexpr Loop(Loop<S, Task>&& o)
|
||||
noexcept(noexcept(Task{std::move(o.task)})):
|
||||
task{std::move(o.task)}, n{std::move(o.n)}
|
||||
{}
|
||||
|
||||
using Signature = Signature_;
|
||||
|
||||
using Struct = S<alsk::Loop, typename Task::Struct>;
|
||||
using Links = L<alsk::Loop, Signature, typename Task::Links>;
|
||||
|
||||
template<typename S>
|
||||
constexpr void setup(S& skeleton) const {
|
||||
skeleton.n = n;
|
||||
setupFor(task, skeleton.task);
|
||||
}
|
||||
|
||||
template<typename Signature>
|
||||
constexpr auto link() const&& {
|
||||
return Loop<Signature, Task>{std::move(*this)};
|
||||
}
|
||||
|
||||
template<typename Signature>
|
||||
constexpr auto link() const& {
|
||||
return Loop<Signature, Task>{*this};
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Signature = void(), typename Task>
|
||||
constexpr auto loop(Task const& task, unsigned int n = 0) {
|
||||
return Loop<Signature, Task>{task, n};
|
||||
}
|
||||
|
||||
template<typename Signature, typename Task>
|
||||
constexpr auto operator&(Farm<Signature, Task> const& farm) {
|
||||
return Loop<Signature, Task>{farm.task, farm.n};
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
67
inc/alsk/edsl/op/impl/operand.h
Normal file
67
inc/alsk/edsl/op/impl/operand.h
Normal file
@ -0,0 +1,67 @@
|
||||
#ifndef ALSK_ALSK_EDSL_OP_IMPL_OPERAND_H
|
||||
#define ALSK_ALSK_EDSL_OP_IMPL_OPERAND_H
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "../../../skeleton/muscle/muscle.h"
|
||||
|
||||
namespace alsk {
|
||||
namespace edsl {
|
||||
|
||||
struct OperandTag;
|
||||
struct LeafTag;
|
||||
|
||||
struct OperandBase {
|
||||
using IsOperand = OperandTag;
|
||||
|
||||
constexpr OperandBase() noexcept = default;
|
||||
|
||||
template<typename S, typename Operand, decltype(std::declval<Operand>().setup(std::declval<S&>()))* = nullptr>
|
||||
constexpr void setupFor(Operand& operand, S& skeleton) const noexcept {
|
||||
operand.setup(skeleton);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
constexpr void setupFor(Args&&...) const noexcept {}
|
||||
};
|
||||
|
||||
template<typename Function_, typename Signature_>
|
||||
struct Operand: OperandBase {
|
||||
using IsLeaf = LeafTag;
|
||||
|
||||
using Function = Function_;
|
||||
using Signature = Signature_;
|
||||
|
||||
using Struct = Function_;
|
||||
using Links = Signature_;
|
||||
|
||||
constexpr Operand() noexcept = default;
|
||||
|
||||
template<typename Signature>
|
||||
constexpr auto link() const noexcept { return Operand<Function, Signature>{}; }
|
||||
};
|
||||
|
||||
template<typename Function>
|
||||
constexpr auto makeOperand() noexcept {
|
||||
return Operand<Function, void()>{};
|
||||
}
|
||||
|
||||
template<typename Signature, typename Function>
|
||||
constexpr auto makeOperand() noexcept {
|
||||
return Operand<Function, Signature>{};
|
||||
}
|
||||
|
||||
template<typename Signature, Signature function>
|
||||
constexpr auto makeOperand() noexcept {
|
||||
using Function = Fn<Signature, function>;
|
||||
return Operand<Function, typename Function::Signature>{};
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// TODO C++17
|
||||
#define alskMakeOperand(f) makeOperand<decltype(f)&, f>()
|
||||
|
||||
#endif
|
120
inc/alsk/edsl/op/impl/serial.h
Normal file
120
inc/alsk/edsl/op/impl/serial.h
Normal file
@ -0,0 +1,120 @@
|
||||
#ifndef ALSK_ALSK_EDSL_OP_IMPL_SERIAL_H
|
||||
#define ALSK_ALSK_EDSL_OP_IMPL_SERIAL_H
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "../traits.h"
|
||||
#include "../../../skeleton/bone/serial.h"
|
||||
#include "../../../skeleton/struct/struct.h"
|
||||
#include "../../../skeleton/link/link.h"
|
||||
|
||||
namespace alsk {
|
||||
namespace edsl {
|
||||
|
||||
template<typename Signature_, typename... Operands>
|
||||
struct Serial: OperandBase {
|
||||
std::tuple<Operands...> operands;
|
||||
|
||||
constexpr Serial(Operands... operands): operands{operands...} {}
|
||||
|
||||
template<typename S>
|
||||
constexpr Serial(Serial<S, Operands...> const& o): operands{o.operands} {}
|
||||
|
||||
template<typename S>
|
||||
constexpr Serial(Serial<S, Operands...>&& o): operands{std::move(o.operands)} {}
|
||||
|
||||
using Signature = Signature_;
|
||||
|
||||
using Struct = S<alsk::Serial, typename Operands::Struct...>;
|
||||
using Links = L<alsk::Serial, Signature, typename Operands::Links...>;
|
||||
|
||||
template<typename S>
|
||||
constexpr void setup(S& skeleton) const {
|
||||
setup(skeleton, std::make_index_sequence<sizeof...(Operands)>());
|
||||
}
|
||||
|
||||
template<typename S, std::size_t... indices>
|
||||
constexpr void setup(S& skeleton, std::index_sequence<indices...>) const {
|
||||
using Expander = int[];
|
||||
static_cast<void>(Expander{(OperandBase::setupFor(std::get<indices>(operands), skeleton.template task<indices>()), 0)...});
|
||||
}
|
||||
|
||||
template<typename Signature>
|
||||
constexpr auto link() const&& {
|
||||
return Serial<Signature, Operands...>{std::move(*this)};
|
||||
}
|
||||
|
||||
template<typename Signature>
|
||||
constexpr auto link() const& {
|
||||
return Serial<Signature, Operands...>{*this};
|
||||
}
|
||||
};
|
||||
|
||||
namespace impl {
|
||||
|
||||
template<typename Lhs, std::size_t... lIndices, typename Rhs, std::size_t... rIndices>
|
||||
constexpr auto mergeSerial(Lhs const& lhs, std::index_sequence<lIndices...>, Rhs const& rhs, std::index_sequence<rIndices...>) {
|
||||
return Serial<void(), std::tuple_element_t<lIndices, Lhs>..., std::tuple_element_t<rIndices, Rhs>...>{
|
||||
std::get<lIndices>(lhs)..., std::get<rIndices>(rhs)...
|
||||
};
|
||||
}
|
||||
|
||||
template<typename Lhs, typename Rhs>
|
||||
constexpr auto mergeSerial(Lhs const& lhs, Rhs const& rhs) {
|
||||
return mergeSerial(lhs, std::make_index_sequence<std::tuple_size<Lhs>{}>(),
|
||||
rhs, std::make_index_sequence<std::tuple_size<Rhs>{}>());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr auto operandTuple(T const& t) {
|
||||
return std::make_tuple(t);
|
||||
}
|
||||
|
||||
template<typename... Ts>
|
||||
constexpr auto operandTuple(Serial<Ts...> const& s) noexcept {
|
||||
return s.operands;
|
||||
}
|
||||
|
||||
template<typename...> struct SerialBuilder;
|
||||
|
||||
template<typename Arg, typename... Args>
|
||||
struct SerialBuilder<Arg, Args...> {
|
||||
static constexpr auto build(Arg const& arg, Args const&... args) {
|
||||
return mergeSerial(operandTuple(arg), operandTuple(SerialBuilder<Args...>::build(args...)));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Arg>
|
||||
struct SerialBuilder<Arg> {
|
||||
static constexpr auto build(Arg const& arg) {
|
||||
return arg;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
template<typename... Args, std::enable_if_t<(sizeof...(Args) > 1) and allOperands<Args...>>* = nullptr>
|
||||
constexpr auto serial(Args const&... args) {
|
||||
return impl::SerialBuilder<Args...>::build(args...);
|
||||
}
|
||||
|
||||
template<
|
||||
typename Lhs, typename Rhs,
|
||||
std::enable_if_t<isOperand<Lhs> and isOperand<Rhs>>* = nullptr
|
||||
>
|
||||
constexpr auto operator,(Lhs const& lhs, Rhs const& rhs) {
|
||||
return impl::mergeSerial(impl::operandTuple(lhs), impl::operandTuple(rhs));
|
||||
}
|
||||
|
||||
template<
|
||||
typename Lhs, typename Rhs,
|
||||
std::enable_if_t<isOperand<Lhs> and isOperand<Rhs>>* = nullptr
|
||||
>
|
||||
constexpr auto operator&(Lhs const& lhs, Rhs const& rhs) {
|
||||
return impl::mergeSerial(impl::operandTuple(lhs), impl::operandTuple(rhs));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
80
inc/alsk/edsl/op/impl/while.h
Normal file
80
inc/alsk/edsl/op/impl/while.h
Normal file
@ -0,0 +1,80 @@
|
||||
#ifndef ALSK_ALSK_EDSL_OP_IMPL_WHILE_H
|
||||
#define ALSK_ALSK_EDSL_OP_IMPL_WHILE_H
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "../traits.h"
|
||||
#include "../../../skeleton/bone/while.h"
|
||||
#include "../../../skeleton/struct/struct.h"
|
||||
#include "../../../skeleton/link/link.h"
|
||||
|
||||
namespace alsk {
|
||||
namespace edsl {
|
||||
|
||||
template<typename Signature_, typename Cond, typename Task>
|
||||
struct While: OperandBase {
|
||||
Cond cond;
|
||||
Task task;
|
||||
|
||||
constexpr While(Cond cond, Task task)
|
||||
noexcept(noexcept(Cond{std::move(cond)}) and noexcept(Task{std::move(task)})):
|
||||
cond{std::move(cond)}, task{std::move(task)}
|
||||
{}
|
||||
|
||||
template<typename S>
|
||||
constexpr While(While<S, Cond, Task> const& o)
|
||||
noexcept(noexcept(Cond{o.cond}) and noexcept(Task{o.task})):
|
||||
cond{o.cond}, task{o.task}
|
||||
{}
|
||||
|
||||
template<typename S>
|
||||
constexpr While(While<S, Cond, Task>&& o)
|
||||
noexcept(noexcept(Cond{std::move(o.cond)}) and noexcept(Task{std::move(o.task)})):
|
||||
cond{std::move(o.cond)}, task{std::move(o.task)}
|
||||
{}
|
||||
|
||||
using Signature = Signature_;
|
||||
|
||||
using Struct = S<alsk::While, typename Cond::Struct, typename Task::Struct>;
|
||||
using Links = L<alsk::While, Signature, typename Cond::Links, typename Task::Links>;
|
||||
|
||||
template<typename S>
|
||||
constexpr void setup(S& skeleton) const {
|
||||
setupFor(cond, skeleton.cond);
|
||||
setupFor(task, skeleton.task);
|
||||
}
|
||||
|
||||
template<typename Signature>
|
||||
constexpr auto link() const&& {
|
||||
return While<Signature, Cond, Task>{std::move(*this)};
|
||||
}
|
||||
|
||||
template<typename Signature>
|
||||
constexpr auto link() const& {
|
||||
return While<Signature, Cond, Task>{*this};
|
||||
}
|
||||
};
|
||||
|
||||
namespace impl {
|
||||
|
||||
template<typename Cond, typename Signature>
|
||||
struct WhilePart {
|
||||
Cond const& cond;
|
||||
|
||||
template<typename Task, std::enable_if_t<isOperand<Task>>* = nullptr>
|
||||
constexpr auto do_(Task const& task) {
|
||||
return alsk::edsl::While<Signature, Cond, Task>{cond, task};
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
template<typename Signature = void(), typename Cond, std::enable_if_t<isOperand<Cond>>* = nullptr>
|
||||
constexpr auto while_(Cond const& cond) {
|
||||
return impl::WhilePart<Cond, Signature>{cond};
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
12
inc/alsk/edsl/op/op.h
Normal file
12
inc/alsk/edsl/op/op.h
Normal file
@ -0,0 +1,12 @@
|
||||
#ifndef ALSK_ALSK_EDSL_OP_OP_H
|
||||
#define ALSK_ALSK_EDSL_OP_OP_H
|
||||
|
||||
#include "impl/farm.h"
|
||||
#include "impl/farmsel.h"
|
||||
#include "impl/itersel.h"
|
||||
#include "impl/loop.h"
|
||||
#include "impl/operand.h"
|
||||
#include "impl/serial.h"
|
||||
#include "impl/while.h"
|
||||
|
||||
#endif
|
82
inc/alsk/edsl/op/traits.h
Normal file
82
inc/alsk/edsl/op/traits.h
Normal file
@ -0,0 +1,82 @@
|
||||
#ifndef ALSK_ALSK_EDSL_OP_TRAITS_H
|
||||
#define ALSK_ALSK_EDSL_OP_TRAITS_H
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include "impl/operand.h"
|
||||
|
||||
namespace alsk {
|
||||
namespace edsl {
|
||||
|
||||
/**
|
||||
* @brief true if the type is an operand for the EDSL
|
||||
*/
|
||||
template<typename, typename=void> struct IsOperand: std::false_type {};
|
||||
|
||||
template<typename T>
|
||||
struct IsOperand<T, std::enable_if_t<std::is_same<typename T::IsOperand, OperandTag>{}>>: std::true_type {};
|
||||
|
||||
template<typename T>
|
||||
constexpr bool isOperand = IsOperand<T>::value;
|
||||
|
||||
/**
|
||||
* @brief true if all the types are operands for the EDSL
|
||||
*/
|
||||
template<typename...> struct AllOperands;
|
||||
|
||||
template<typename T, typename... Ts>
|
||||
struct AllOperands<T, Ts...> {
|
||||
static constexpr bool value = isOperand<T> && AllOperands<Ts...>::value;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct AllOperands<>: std::true_type {};
|
||||
|
||||
template<typename... Ts>
|
||||
constexpr bool allOperands = AllOperands<Ts...>::value;
|
||||
|
||||
/**
|
||||
* @brief true if the type is a leaf
|
||||
*/
|
||||
template<typename, typename=void> struct IsLeaf: std::false_type {};
|
||||
|
||||
template<typename T>
|
||||
struct IsLeaf<T, std::enable_if_t<std::is_same<typename T::IsLeaf, LeafTag>{}>>: std::true_type {};
|
||||
|
||||
template<typename T>
|
||||
constexpr bool isLeaf = IsLeaf<T>::value;
|
||||
|
||||
/**
|
||||
* @brief true if the type is a branch
|
||||
*/
|
||||
template<typename, typename=void> struct IsBranch: std::false_type {};
|
||||
|
||||
template<typename T>
|
||||
struct IsBranch<T, std::enable_if_t<isOperand<T> and not isLeaf<T>>>: std::true_type {};
|
||||
|
||||
template<typename T>
|
||||
constexpr bool isBranch = IsBranch<T>::value;
|
||||
|
||||
/**
|
||||
* @brief get the return value from an operand's signature
|
||||
*/
|
||||
template<typename> struct GetReturnTypeFromSignatureImpl;
|
||||
|
||||
template<typename R, typename... Args>
|
||||
struct GetReturnTypeFromSignatureImpl<R(Args...)> {
|
||||
using type = R;
|
||||
};
|
||||
|
||||
template<typename Signature>
|
||||
using GetReturnTypeFromSignature = typename GetReturnTypeFromSignatureImpl<Signature>::type;
|
||||
|
||||
/**
|
||||
* @brief get the return value from an operand
|
||||
*/
|
||||
template<typename T>
|
||||
using GetReturnType = GetReturnTypeFromSignature<typename T::Signature>;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
13
inc/alsk/executor/executor.h
Normal file
13
inc/alsk/executor/executor.h
Normal file
@ -0,0 +1,13 @@
|
||||
#ifndef ALSK_ALSK_EXECUTOR_EXECUTOR_H
|
||||
#define ALSK_ALSK_EXECUTOR_EXECUTOR_H
|
||||
|
||||
#include "impl/dynamicpool.h"
|
||||
#include "impl/firstlevel/equi.h"
|
||||
#include "impl/firstlevel/greedy.h"
|
||||
#include "impl/firstlevel/noopti.h"
|
||||
#include "impl/sequential.h"
|
||||
#include "impl/staticpool.h"
|
||||
#include "impl/staticpoolid.h"
|
||||
#include "impl/staticthread.h"
|
||||
|
||||
#endif
|
125
inc/alsk/executor/executorbase.h
Normal file
125
inc/alsk/executor/executorbase.h
Normal file
@ -0,0 +1,125 @@
|
||||
#ifndef ALSK_ALSK_EXECUTOR_EXECUTORBASE_H
|
||||
#define ALSK_ALSK_EXECUTOR_EXECUTORBASE_H
|
||||
|
||||
#include <algorithm>
|
||||
#include <thread>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "tags.h"
|
||||
#include "../impl/tags.h"
|
||||
|
||||
namespace alsk {
|
||||
namespace exec {
|
||||
|
||||
struct ExecutorBase {
|
||||
using IsExecutor = tag::Executor;
|
||||
|
||||
public:
|
||||
struct Info {};
|
||||
|
||||
struct RCores {
|
||||
std::vector<std::size_t> coresList;
|
||||
|
||||
RCores() { upTo(std::thread::hardware_concurrency()); }
|
||||
|
||||
/**
|
||||
* @brief disables repeatability
|
||||
*/
|
||||
void disabled() noexcept { coresList.clear(); }
|
||||
|
||||
/**
|
||||
* @brief defines possibles cores from min to n by given step
|
||||
* @param n possibly included upper bound, if 0 or 1, disables repeatability
|
||||
* @param min lower bound (at least 2, at most n)
|
||||
* @param step step (at least 1)
|
||||
*/
|
||||
void upTo(std::size_t n, std::size_t min = 2, std::size_t step = 1) {
|
||||
coresList.clear();
|
||||
if(n < 2) return;
|
||||
std::size_t k = (n-min+step) / step;
|
||||
coresList.resize(k);
|
||||
std::generate_n(std::begin(coresList), n-1, [i=0, &min, &step]() mutable { return (min+step*i++); });
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief defines possibles cores from min to n, multiplying by given step
|
||||
* @param n possibly included upper bound, if 0 or 1, disables repeatability
|
||||
* @param min lower bound (at least 2, at most n)
|
||||
* @param step step (at least 2)
|
||||
*/
|
||||
void expUpTo(std::size_t n, std::size_t min = 2, std::size_t step = 2) {
|
||||
coresList.clear();
|
||||
if(n < 2) return;
|
||||
while(min <= n) {
|
||||
coresList.push_back(min);
|
||||
min *= step;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief defines possibles cores from min to n, multiplying by given step
|
||||
* @param args all cores to support
|
||||
*/
|
||||
template<typename... Args>
|
||||
void forValues(Args&&... args) {
|
||||
coresList = {std::forward<Args>(args)...};
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief set this variable to the number of allotted cores
|
||||
*/
|
||||
std::size_t cores;
|
||||
|
||||
/**
|
||||
* @brief this variable allows to configure repeatability
|
||||
*/
|
||||
RCores repeatability;
|
||||
|
||||
public:
|
||||
ExecutorBase(): cores{std::thread::hardware_concurrency()} {}
|
||||
|
||||
public:
|
||||
template<typename Impl>
|
||||
void config(Impl&) {}
|
||||
|
||||
template<typename Impl>
|
||||
std::size_t contextIdCount(Impl&, std::size_t id) { return id; }
|
||||
|
||||
template<typename Impl>
|
||||
std::size_t contextId(Impl&, std::size_t id) { return id; }
|
||||
|
||||
template<typename Task, typename Impl, typename BTask, typename Parameters, typename Results, typename... Args>
|
||||
decltype(auto) execute(Impl& impl, BTask& task, Parameters&& parameters, Results&& results, Args&&... args) {
|
||||
return _execute<Task>(impl, task, impl.executorInfo, std::forward<Parameters>(parameters), std::forward<Results>(results),
|
||||
std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename Task, typename Impl, typename BTask, typename Parameters>
|
||||
void executeSequential(Impl& impl, BTask& task, Parameters&& parameters, std::size_t n) {
|
||||
return _executeSequential<Task>(impl, task, impl.executorInfo, std::forward<Parameters>(parameters), n);
|
||||
}
|
||||
|
||||
protected:
|
||||
template<typename Task, typename Impl, typename BTask, typename Info, typename Parameters, typename Results, typename... Args>
|
||||
decltype(auto) _execute(Impl& impl, BTask& task, Info&& info, Parameters&& parameters, Results&& results, Args&&... args) {
|
||||
return Task::execute(
|
||||
impl, task, 0, std::forward<Info>(info), std::forward<Parameters>(parameters), std::forward<Results>(results),
|
||||
std::forward<Args>(args)...
|
||||
);
|
||||
}
|
||||
|
||||
template<typename Task, typename Impl, typename BTask, typename Info, typename Parameters>
|
||||
void _executeSequential(Impl& impl, BTask& task, Info const& info, Parameters const& parameters, std::size_t n) {
|
||||
for(std::size_t i = 0; i < n; ++i)
|
||||
Task::execute(impl, task, i, info, parameters, std::tuple<>{});
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
12
inc/alsk/executor/executorstate.h
Normal file
12
inc/alsk/executor/executorstate.h
Normal file
@ -0,0 +1,12 @@
|
||||
#ifndef ALSK_ALSK_EXECUTOR_EXECUTORSTATE_H
|
||||
#define ALSK_ALSK_EXECUTOR_EXECUTORSTATE_H
|
||||
|
||||
namespace alsk {
|
||||
namespace exec {
|
||||
|
||||
template<typename> struct ExecutorState;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
123
inc/alsk/executor/impl/dynamicpool.h
Normal file
123
inc/alsk/executor/impl/dynamicpool.h
Normal file
@ -0,0 +1,123 @@
|
||||
#ifndef ALSK_ALSK_EXECUTOR_IMPL_DYNAMICPOOL_H
|
||||
#define ALSK_ALSK_EXECUTOR_IMPL_DYNAMICPOOL_H
|
||||
|
||||
#include <algorithm>
|
||||
#include <future>
|
||||
#include <vector>
|
||||
|
||||
#include "../executorbase.h"
|
||||
#include "../executorstate.h"
|
||||
#include "../../skeleton/traits.h"
|
||||
|
||||
#include "../utility/pool.h"
|
||||
|
||||
namespace alsk {
|
||||
namespace exec {
|
||||
|
||||
template<typename S>
|
||||
struct DynamicPool: ExecutorBase {
|
||||
using Tag = alsk::tag::Parallel;
|
||||
|
||||
public:
|
||||
std::size_t maxTaskCount = 1'000;
|
||||
|
||||
public:
|
||||
template<typename Impl>
|
||||
void config(Impl& impl) {
|
||||
impl.state.executor.config(cores);
|
||||
}
|
||||
|
||||
template<typename Task, typename Impl, typename BTask, typename Parameters>
|
||||
void executeParallel(Impl& impl, BTask& task, Parameters const& parameters, std::size_t n) {
|
||||
std::size_t taskCount = std::min(maxTaskCount, n);
|
||||
|
||||
if(cores > 1 && taskCount > 1) {
|
||||
Info info;
|
||||
std::vector<std::future<void>> futures(taskCount);
|
||||
std::size_t const step = n/taskCount;
|
||||
std::size_t const remain = n - step*(taskCount-1);
|
||||
|
||||
typename Impl::State& state = impl.state;
|
||||
|
||||
auto run = [&](std::size_t b, std::size_t k) {
|
||||
for(std::size_t i = 0; i < k; ++i)
|
||||
Task::execute(impl, task, b+i, info, parameters, std::tuple<>{});
|
||||
};
|
||||
|
||||
for(std::size_t i = 0; i < taskCount-1; ++i)
|
||||
futures[i] = state.executor.run([&, b=i*step, k=step]{ run(b, k); });
|
||||
futures[taskCount-1] = state.executor.run([&, b=(taskCount-1)*step, k=remain]{ run(b, k); });
|
||||
|
||||
state.executor.wait(futures);
|
||||
} else {
|
||||
Info info;
|
||||
for(std::size_t i = 0; i < n; ++i)
|
||||
Task::execute(impl, task, i, info, parameters, std::tuple<>{});
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Value, typename Task, typename Select, typename Impl, typename BTask, typename BSelect, typename Parameters>
|
||||
Value executeParallelAccumulate(Impl& impl, BTask& task, BSelect& select, Parameters const& parameters, std::size_t n) {
|
||||
std::size_t taskCount = std::min(maxTaskCount, n);
|
||||
|
||||
Value best{};
|
||||
|
||||
if(cores > 1 && taskCount > 1) {
|
||||
Info info;
|
||||
std::vector<std::future<void>> futures(taskCount);
|
||||
std::size_t const step = n/taskCount;
|
||||
std::size_t const remainBase = n - step*taskCount;
|
||||
std::size_t remain = remainBase;
|
||||
|
||||
typename Impl::State& state = impl.state;
|
||||
|
||||
auto run = [&](Value& out, std::size_t b, std::size_t k) {
|
||||
Value best{};
|
||||
|
||||
if(k)
|
||||
best = Task::execute(impl, task, b+0, info, parameters, std::tuple<>{});
|
||||
for(std::size_t i = 1; i < k; ++i) {
|
||||
Value current = Task::execute(impl, task, b+i, info, parameters, std::tuple<>{});
|
||||
best = Select::execute(impl, select, b+i, info, parameters, std::tuple<>{}, std::move(current), std::move(best));
|
||||
}
|
||||
|
||||
out = std::move(best);
|
||||
};
|
||||
|
||||
std::size_t start{};
|
||||
std::vector<Value> bests(taskCount);
|
||||
for(std::size_t i = 0; i < taskCount-1; ++i) {
|
||||
std::size_t offset = !!remain;
|
||||
remain -= offset;
|
||||
futures[i] = state.executor.run([&, &best=bests[i], b=start, k=step+offset] { run(best, b, k); });
|
||||
start += step+offset;
|
||||
}
|
||||
|
||||
futures[taskCount-1] = state.executor.run([&, &best=bests[taskCount-1], b=start, k=step] { run(best, b, k); });
|
||||
|
||||
state.executor.wait(futures);
|
||||
|
||||
if(taskCount) best = std::move(bests[0]);
|
||||
for(std::size_t i = 1; i < taskCount; ++i)
|
||||
best = Select::execute(impl, select, i, info, parameters, std::tuple<>{}, std::move(bests[i]), std::move(best));
|
||||
} else {
|
||||
Info info;
|
||||
if(n)
|
||||
best = Task::execute(impl, task, 0, info, parameters, std::tuple<>{});
|
||||
for(std::size_t i = 1; i < n; ++i) {
|
||||
Value current = Task::execute(impl, task, i, info, parameters, std::tuple<>{});
|
||||
best = Select::execute(impl, select, i, info, parameters, std::tuple<>{}, std::move(current), std::move(best));
|
||||
}
|
||||
}
|
||||
|
||||
return best;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename S>
|
||||
struct ExecutorState<DynamicPool<S>>: util::Pool {};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
195
inc/alsk/executor/impl/firstlevel/equi.h
Normal file
195
inc/alsk/executor/impl/firstlevel/equi.h
Normal file
@ -0,0 +1,195 @@
|
||||
#ifndef ALSK_ALSK_EXECUTOR_IMPL_FIRSTLEVEL_EQUI_H
|
||||
#define ALSK_ALSK_EXECUTOR_IMPL_FIRSTLEVEL_EQUI_H
|
||||
|
||||
#include <cmath>
|
||||
#include <thread>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
#include "../../executorbase.h"
|
||||
#include "../../executorstate.h"
|
||||
#include "../../../skeleton/traits.h"
|
||||
|
||||
namespace alsk {
|
||||
namespace exec {
|
||||
|
||||
template<typename S>
|
||||
struct FirstLevelEqui: ExecutorBase {
|
||||
using Tag = alsk::tag::Parallel;
|
||||
|
||||
public:
|
||||
struct Info {
|
||||
unsigned int parDepth;
|
||||
|
||||
Info(unsigned int parDepth = 0) noexcept: parDepth{parDepth} {}
|
||||
|
||||
Info par() const noexcept { return {parDepth+1}; }
|
||||
Info seq() const noexcept { return {parDepth}; }
|
||||
};
|
||||
|
||||
private:
|
||||
template<typename Impl>
|
||||
void buildSplit(Impl& impl) {
|
||||
typename Impl::State& state = impl.state;
|
||||
auto& split = state.executor.split;
|
||||
|
||||
split.clear();
|
||||
|
||||
auto traverser = [](std::size_t, auto&& skl, auto&&... values) {
|
||||
using Skl = decltype(skl);
|
||||
using Traits = SkeletonTraitsT<std::decay_t<Skl>>;
|
||||
if(Traits::serial) return max(decltype(values)(values)...);
|
||||
return Traits::parallelizability(std::forward<Skl>(skl));
|
||||
};
|
||||
|
||||
auto firstLevelPar = SkeletonTraversal<S>::execute(impl.skeleton, traverser, 1ul);
|
||||
|
||||
split.insert(0);
|
||||
for(auto const& k: repeatability.coresList) {
|
||||
std::size_t start{};
|
||||
std::size_t const step = firstLevelPar/k;
|
||||
std::size_t remain = firstLevelPar - step*k;
|
||||
|
||||
for(unsigned int i = 0; i < k-1; ++i) {
|
||||
std::size_t offset = !!remain;
|
||||
remain -= offset;
|
||||
start += step+offset;
|
||||
split.insert(start * (state.executor.parTasksCount/firstLevelPar));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int threadLimit(Info const& info) const noexcept {
|
||||
return info.parDepth? 1 : cores;
|
||||
}
|
||||
|
||||
public:
|
||||
template<typename Impl>
|
||||
void config(Impl& impl) {
|
||||
typename Impl::State& state = impl.state;
|
||||
|
||||
state.executor.parTasksCount = impl.parallelTasksCount();;
|
||||
buildSplit(impl);
|
||||
}
|
||||
|
||||
template<typename Impl>
|
||||
std::size_t contextIdCount(Impl& impl, std::size_t) {
|
||||
typename Impl::State& state = impl.state;
|
||||
return state.executor.split.size();
|
||||
}
|
||||
|
||||
template<typename Impl>
|
||||
std::size_t contextId(Impl& impl, std::size_t id) { // O(log(n))
|
||||
typename Impl::State& state = impl.state;
|
||||
auto& split = state.executor.split;
|
||||
return std::distance(std::begin(split), split.upper_bound(id)) - 1;
|
||||
}
|
||||
|
||||
template<typename Task, typename Impl, typename BTask, typename Parameters>
|
||||
void executeParallel(Impl& impl, BTask& task, Parameters const& parameters, std::size_t n) {
|
||||
std::size_t const maxThreads = threadLimit(impl.executorInfo);
|
||||
std::size_t const nThreads = std::min(n, maxThreads);
|
||||
|
||||
if(nThreads > 1) {
|
||||
Info info = impl.executorInfo.par();
|
||||
std::vector<std::thread> threads(nThreads-1);
|
||||
std::size_t const step = n/nThreads;
|
||||
std::size_t const remainBase = n - step*nThreads;
|
||||
std::size_t remain = remainBase;
|
||||
|
||||
auto run = [&](std::size_t b, std::size_t k) {
|
||||
for(std::size_t i = 0; i < k; ++i)
|
||||
Task::execute(impl, task, b+i, info, parameters, std::tuple<>{});
|
||||
};
|
||||
|
||||
{
|
||||
std::size_t start{};
|
||||
for(std::size_t i = 0; i < nThreads-1; ++i) {
|
||||
std::size_t offset = !!remain;
|
||||
remain -= offset;
|
||||
threads[i] = std::thread{run, start, step+offset};
|
||||
start += step+offset;
|
||||
}
|
||||
|
||||
run(start, step);
|
||||
}
|
||||
|
||||
for(std::thread& thread: threads) thread.join();
|
||||
} else {
|
||||
Info info = impl.executorInfo.seq();
|
||||
for(std::size_t i = 0; i < n; ++i)
|
||||
Task::execute(impl, task, i, info, parameters, std::tuple<>{});
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Value, typename Task, typename Select, typename Impl, typename BTask, typename BSelect, typename Parameters>
|
||||
Value executeParallelAccumulate(Impl& impl, BTask& task, BSelect& select, Parameters const& parameters, std::size_t n) {
|
||||
std::size_t const maxThreads = threadLimit(impl.executorInfo); // TODO? fix neighbours
|
||||
|
||||
Value best{};
|
||||
|
||||
std::size_t const nThreads = std::min(n, maxThreads);
|
||||
if(nThreads > 1) {
|
||||
Info info = impl.executorInfo.par();
|
||||
std::vector<std::thread> threads(nThreads-1);
|
||||
std::size_t const step = n/nThreads;
|
||||
std::size_t const remainBase = n - step*nThreads;
|
||||
std::size_t remain = remainBase;
|
||||
|
||||
auto run = [&](Value& out, std::size_t b, std::size_t k) {
|
||||
Value best{};
|
||||
|
||||
if(k)
|
||||
best = Task::execute(impl, task, b+0, info, parameters, std::tuple<>{});
|
||||
for(std::size_t i = 1; i < k; ++i) {
|
||||
Value current = Task::execute(impl, task, b+i, info, parameters, std::tuple<>{});
|
||||
best = Select::execute(impl, select, b+i, info, parameters, std::tuple<>{}, std::move(current), std::move(best));
|
||||
}
|
||||
|
||||
out = std::move(best);
|
||||
};
|
||||
|
||||
std::size_t start{};
|
||||
std::vector<Value> bests(nThreads);
|
||||
|
||||
{
|
||||
std::size_t i;
|
||||
for(i = 0; i < nThreads-1; ++i) {
|
||||
std::size_t offset = !!remain;
|
||||
remain -= offset;
|
||||
threads[i] = std::thread{run, std::ref(bests[i]), start, step+offset};
|
||||
start += step+offset;
|
||||
}
|
||||
|
||||
run(bests[i], start, step);
|
||||
}
|
||||
|
||||
for(std::thread& thread: threads) thread.join();
|
||||
|
||||
if(nThreads) best = std::move(bests[0]);
|
||||
for(std::size_t i = 1; i < nThreads; ++i)
|
||||
best = Select::execute(impl, select, i, info, parameters, std::tuple<>{}, std::move(bests[i]), std::move(best));
|
||||
} else {
|
||||
Info info = impl.executorInfo.seq();
|
||||
if(n)
|
||||
best = Task::execute(impl, task, 0, info, parameters, std::tuple<>{});
|
||||
for(std::size_t i = 1; i < n; ++i) {
|
||||
Value current = Task::execute(impl, task, i, info, parameters, std::tuple<>{});
|
||||
best = Select::execute(impl, select, i, info, parameters, std::tuple<>{}, std::move(current), std::move(best));
|
||||
}
|
||||
}
|
||||
|
||||
return best;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename S>
|
||||
struct ExecutorState<FirstLevelEqui<S>> {
|
||||
std::size_t parTasksCount;
|
||||
std::set<std::size_t> split;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
168
inc/alsk/executor/impl/firstlevel/greedy.h
Normal file
168
inc/alsk/executor/impl/firstlevel/greedy.h
Normal file
@ -0,0 +1,168 @@
|
||||
#ifndef ALSK_ALSK_EXECUTOR_IMPL_FIRSTLEVEL_GREEDY_H
|
||||
#define ALSK_ALSK_EXECUTOR_IMPL_FIRSTLEVEL_GREEDY_H
|
||||
|
||||
#include <cmath>
|
||||
#include <thread>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
#include "../../executorbase.h"
|
||||
#include "../../executorstate.h"
|
||||
#include "../../../skeleton/traits.h"
|
||||
|
||||
namespace alsk {
|
||||
namespace exec {
|
||||
|
||||
template<typename S>
|
||||
struct FirstLevelGreedy: ExecutorBase {
|
||||
using Tag = alsk::tag::Parallel;
|
||||
|
||||
public:
|
||||
struct Info {
|
||||
unsigned int parDepth;
|
||||
};
|
||||
|
||||
private:
|
||||
template<typename Impl>
|
||||
void buildSplit(Impl& impl) {
|
||||
typename Impl::State& state = impl.state;
|
||||
auto& split = state.executor.split;
|
||||
|
||||
split.clear();
|
||||
|
||||
auto traverser = [](std::size_t, auto&& skl, auto&&... values) {
|
||||
using Skl = decltype(skl);
|
||||
using Traits = alsk::SkeletonTraitsT<Skl>;
|
||||
if(Traits::serial) return max(values...);
|
||||
return Traits::parallelizability(std::forward<Skl>(skl));
|
||||
};
|
||||
|
||||
auto firstLevelPar = SkeletonTraversal<S>::execute(impl.skeleton, traverser, 1ul);
|
||||
|
||||
split.insert(0);
|
||||
for(auto const& k: repeatability.coresList) {
|
||||
std::size_t start{};
|
||||
std::size_t const step = (firstLevelPar + k-1)/k;
|
||||
std::size_t const rk = (firstLevelPar + step-1)/step;
|
||||
|
||||
for(unsigned int i = 0; i < rk; ++i, start += step)
|
||||
split.insert(start * (state.executor.parTasksCount/firstLevelPar));
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int threadLimit(unsigned int level) const { return level? 1 : cores; }
|
||||
|
||||
public:
|
||||
template<typename Impl>
|
||||
void config(Impl& impl) {
|
||||
typename Impl::State& state = impl.state;
|
||||
|
||||
state.executor.parTasksCount = impl.parallelTasksCount();;
|
||||
buildSplit(impl);
|
||||
}
|
||||
|
||||
template<typename Impl>
|
||||
std::size_t contextIdCount(Impl& impl, std::size_t) {
|
||||
typename Impl::State& state = impl.state;
|
||||
return state.executor.split.size();
|
||||
}
|
||||
|
||||
template<typename Impl>
|
||||
std::size_t contextId(Impl& impl, std::size_t id) { // O(log(n))
|
||||
typename Impl::State& state = impl.state;
|
||||
auto& split = state.executor.split;
|
||||
return std::distance(std::begin(split), split.upper_bound(id)) - 1;
|
||||
}
|
||||
|
||||
template<typename Task, typename Impl, typename BTask, typename Parameters>
|
||||
void executeParallel(Impl& impl, BTask& task, Parameters const& parameters, std::size_t n) {
|
||||
auto const& parDepth = impl.executorInfo.parDepth;
|
||||
std::size_t const maxThreads = threadLimit(parDepth);
|
||||
|
||||
std::size_t const nThreads = std::min(n, maxThreads);
|
||||
if(nThreads > 1) {
|
||||
Info info{parDepth+1};
|
||||
std::vector<std::thread> threads(nThreads-1);
|
||||
std::size_t const step = std::round(static_cast<double>(n)/nThreads);
|
||||
|
||||
auto run = [&](std::size_t b, std::size_t k) {
|
||||
for(std::size_t i = 0; i < k; ++i)
|
||||
Task::execute(impl, task, b+i, info, parameters, std::tuple<>{});
|
||||
};
|
||||
|
||||
for(std::size_t i = 0; i < nThreads-1; ++i)
|
||||
threads[i] = std::thread{run, i*step, step};
|
||||
|
||||
run((nThreads-1)*step, n-(nThreads-1)*step);
|
||||
|
||||
for(std::thread& thread: threads) thread.join();
|
||||
} else {
|
||||
Info info{parDepth};
|
||||
for(std::size_t i = 0; i < n; ++i)
|
||||
Task::execute(impl, task, i, info, parameters, std::tuple<>{});
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Value, typename Task, typename Select, typename Impl, typename BTask, typename BSelect, typename Parameters>
|
||||
Value executeParallelAccumulate(Impl& impl, BTask& task, BSelect& select, Parameters const& parameters, std::size_t n) {
|
||||
auto const& parDepth = impl.executorInfo.parDepth;
|
||||
std::size_t const maxThreads = threadLimit(parDepth); // TODO fix neighbours
|
||||
|
||||
Value best{};
|
||||
|
||||
std::size_t const nThreadsBase = std::min(n, maxThreads);
|
||||
if(nThreadsBase > 1) {
|
||||
Info info{parDepth+1};
|
||||
std::size_t const step = (n+nThreadsBase-1)/nThreadsBase;
|
||||
std::size_t const nThreads = (n+step-1)/step;
|
||||
std::vector<std::thread> threads(nThreads-1);
|
||||
|
||||
auto run = [&](Value& out, std::size_t b, std::size_t k) {
|
||||
Value best{};
|
||||
|
||||
if(k)
|
||||
best = Task::execute(impl, task, b+0, info, parameters, std::tuple<>{});
|
||||
for(std::size_t i = 1; i < k; ++i) {
|
||||
Value current = Task::execute(impl, task, b+i, info, parameters, std::tuple<>{});
|
||||
best = Select::execute(impl, select, b+i, info, parameters, std::tuple<>{}, std::move(current), std::move(best));
|
||||
}
|
||||
|
||||
out = std::move(best);
|
||||
};
|
||||
|
||||
std::size_t start{};
|
||||
std::vector<Value> bests(nThreads);
|
||||
for(std::size_t i = 0; i < nThreads-1; ++i, start += step)
|
||||
threads[i] = std::thread{run, std::ref(bests[i]), start, step};
|
||||
|
||||
run(bests[nThreads-1], start, n - step*(nThreads-1));
|
||||
|
||||
for(std::thread& thread: threads) thread.join();
|
||||
|
||||
if(nThreads) best = std::move(bests[0]);
|
||||
for(std::size_t i = 1; i < nThreads; ++i)
|
||||
best = Select::execute(impl, select, i, info, parameters, std::tuple<>{}, std::move(bests[i]), std::move(best));
|
||||
} else {
|
||||
Info info{parDepth};
|
||||
if(n)
|
||||
best = Task::execute(impl, task, 0, info, parameters, std::tuple<>{});
|
||||
for(std::size_t i = 1; i < n; ++i) {
|
||||
Value current = Task::execute(impl, task, i, info, parameters, std::tuple<>{});
|
||||
best = Select::execute(impl, select, i, info, parameters, std::tuple<>{}, std::move(current), std::move(best));
|
||||
}
|
||||
}
|
||||
|
||||
return best;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename S>
|
||||
struct ExecutorState<FirstLevelGreedy<S>> {
|
||||
std::size_t parTasksCount;
|
||||
std::set<std::size_t> split;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
129
inc/alsk/executor/impl/firstlevel/noopti.h
Normal file
129
inc/alsk/executor/impl/firstlevel/noopti.h
Normal file
@ -0,0 +1,129 @@
|
||||
#ifndef ALSK_ALSK_EXECUTOR_IMPL_FIRSTLEVEL_NOOPTI_H
|
||||
#define ALSK_ALSK_EXECUTOR_IMPL_FIRSTLEVEL_NOOPTI_H
|
||||
|
||||
#include <thread>
|
||||
#include <set>
|
||||
#include <cmath>
|
||||
#include <vector>
|
||||
|
||||
#include "../../executorbase.h"
|
||||
#include "../../executorstate.h"
|
||||
#include "../../../skeleton/traits.h"
|
||||
|
||||
namespace alsk {
|
||||
namespace exec {
|
||||
|
||||
template<typename S>
|
||||
struct FirstLevelNoOpti: ExecutorBase {
|
||||
using Tag = alsk::tag::Parallel;
|
||||
|
||||
public:
|
||||
struct Info {
|
||||
unsigned int parDepth;
|
||||
};
|
||||
|
||||
private:
|
||||
unsigned int threadLimit(unsigned int level) const { return level? 1 : cores; }
|
||||
|
||||
public:
|
||||
template<typename Impl>
|
||||
std::size_t contextIdCount(Impl&, std::size_t count) { return count; }
|
||||
|
||||
template<typename Impl>
|
||||
std::size_t contextId(Impl&, std::size_t id) { return id; }
|
||||
|
||||
template<typename Task, typename Impl, typename BTask, typename Parameters>
|
||||
void executeParallel(Impl& impl, BTask& task, Parameters const& parameters, std::size_t n) {
|
||||
auto const& parDepth = impl.executorInfo.parDepth;
|
||||
std::size_t const maxThreads = threadLimit(parDepth);
|
||||
|
||||
std::size_t const nThreads = std::min(n, maxThreads);
|
||||
if(nThreads > 1) {
|
||||
Info info{parDepth+1};
|
||||
std::vector<std::thread> threads(nThreads-1);
|
||||
std::size_t const step = std::round(static_cast<double>(n)/nThreads);
|
||||
|
||||
auto run = [&](std::size_t b, std::size_t k) {
|
||||
for(std::size_t i = 0; i < k; ++i)
|
||||
Task::execute(impl, task, b+i, info, parameters, std::tuple<>{});
|
||||
};
|
||||
|
||||
for(std::size_t i = 0; i < nThreads-1; ++i)
|
||||
threads[i] = std::thread{run, i*step, step};
|
||||
|
||||
run((nThreads-1)*step, n-(nThreads-1)*step);
|
||||
|
||||
for(std::thread& thread: threads) thread.join();
|
||||
|
||||
} else {
|
||||
Info info{parDepth};
|
||||
for(std::size_t i = 0; i < n; ++i)
|
||||
Task::execute(impl, task, i, info, parameters, std::tuple<>{});
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Value, typename Task, typename Select, typename Impl, typename BTask, typename BSelect, typename Parameters>
|
||||
Value executeParallelAccumulate(Impl& impl, BTask& task, BSelect& select, Parameters const& parameters, std::size_t n) {
|
||||
auto const& parDepth = impl.executorInfo.parDepth;
|
||||
std::size_t const maxThreads = threadLimit(parDepth); // TODO fix neighbours
|
||||
|
||||
Value best{};
|
||||
|
||||
std::size_t const nThreads = std::min(n, maxThreads);
|
||||
if(nThreads > 1) {
|
||||
Info info{parDepth+1};
|
||||
std::vector<std::thread> threads(nThreads-1);
|
||||
std::size_t const step = n/nThreads;
|
||||
std::size_t const remainBase = n - step*nThreads;
|
||||
std::size_t remain = remainBase;
|
||||
|
||||
auto run = [&](Value& out, std::size_t b, std::size_t k) {
|
||||
Value best{};
|
||||
|
||||
if(k)
|
||||
best = Task::execute(impl, task, b+0, info, parameters, std::tuple<>{});
|
||||
for(std::size_t i = 1; i < k; ++i) {
|
||||
Value current = Task::execute(impl, task, b+i, info, parameters, std::tuple<>{});
|
||||
best = Select::execute(impl, select, b+i, info, parameters, std::tuple<>{}, std::move(current), std::move(best));
|
||||
}
|
||||
|
||||
out = std::move(best);
|
||||
};
|
||||
|
||||
std::size_t start{};
|
||||
std::vector<Value> bests(nThreads);
|
||||
for(std::size_t i = 0; i < nThreads-1; ++i) {
|
||||
std::size_t offset = !!remain;
|
||||
remain -= offset;
|
||||
threads[i] = std::thread{run, std::ref(bests[i]), start, step+offset};
|
||||
start += step+offset;
|
||||
}
|
||||
|
||||
run(bests[nThreads-1], start, step);
|
||||
|
||||
for(std::thread& thread: threads) thread.join();
|
||||
|
||||
if(nThreads) best = std::move(bests[0]);
|
||||
for(std::size_t i = 1; i < nThreads; ++i)
|
||||
best = Select::execute(impl, select, i, info, parameters, std::tuple<>{}, std::move(bests[i]), std::move(best));
|
||||
} else {
|
||||
Info info{parDepth};
|
||||
if(n)
|
||||
best = Task::execute(impl, task, 0, info, parameters, std::tuple<>{});
|
||||
for(std::size_t i = 1; i < n; ++i) {
|
||||
Value current = Task::execute(impl, task, i, info, parameters, std::tuple<>{});
|
||||
best = Select::execute(impl, select, i, info, parameters, std::tuple<>{}, std::move(current), std::move(best));
|
||||
}
|
||||
}
|
||||
|
||||
return best;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename S>
|
||||
struct ExecutorState<FirstLevelNoOpti<S>> {};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user