2019-01-03 19:54:50 +05:00
|
|
|
#include <mutex>
|
|
|
|
|
|
|
|
#include "profiler.hpp"
|
|
|
|
|
|
|
|
namespace ngcore
|
|
|
|
{
|
2019-01-07 15:26:46 +05:00
|
|
|
std::vector<NgProfiler::TimerVal> NgProfiler::timers(NgProfiler::SIZE); // NOLINT
|
2019-01-03 19:54:50 +05:00
|
|
|
|
|
|
|
std::string NgProfiler::filename;
|
|
|
|
|
2019-04-25 01:21:05 +05:00
|
|
|
std::array<size_t,NgProfiler::SIZE> NgProfiler::dummy_thread_times;
|
|
|
|
size_t * NgProfiler::thread_times = NgProfiler::dummy_thread_times.data(); // NOLINT
|
|
|
|
std::array<size_t,NgProfiler::SIZE> NgProfiler::dummy_thread_flops;
|
|
|
|
size_t * NgProfiler::thread_flops = NgProfiler::dummy_thread_flops.data(); // NOLINT
|
2019-01-03 19:54:50 +05:00
|
|
|
|
2019-01-16 18:33:48 +05:00
|
|
|
std::shared_ptr<Logger> NgProfiler::logger = GetLogger("Profiler"); // NOLINT
|
2019-01-03 19:54:50 +05:00
|
|
|
|
|
|
|
NgProfiler :: NgProfiler()
|
|
|
|
{
|
|
|
|
for (auto & t : timers)
|
|
|
|
{
|
|
|
|
t.tottime = 0.0;
|
|
|
|
t.usedcounter = 0;
|
|
|
|
t.flops = 0.0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
NgProfiler :: ~NgProfiler()
|
|
|
|
{
|
|
|
|
if (filename.length())
|
|
|
|
{
|
|
|
|
logger->debug( "write profile to file {}", filename );
|
|
|
|
FILE *prof = fopen(filename.c_str(),"w"); // NOLINT
|
|
|
|
Print (prof);
|
|
|
|
fclose(prof); // NOLINT
|
|
|
|
}
|
|
|
|
|
2019-01-14 17:04:27 +05:00
|
|
|
if (getenv ("NGPROFILE"))
|
|
|
|
{
|
|
|
|
std::string filename = "netgen.prof";
|
|
|
|
#ifdef PARALLEL
|
|
|
|
filename += "."+ToString(id);
|
|
|
|
#endif
|
|
|
|
if (id == 0) logger->info( "write profile to file {}", filename );
|
|
|
|
FILE *prof = fopen(filename.c_str(),"w"); // NOLINT
|
|
|
|
Print (prof);
|
|
|
|
fclose(prof); // NOLINT
|
|
|
|
}
|
2019-01-03 19:54:50 +05:00
|
|
|
}
|
|
|
|
|
|
|
|
void NgProfiler :: Print (FILE * prof)
|
|
|
|
{
|
|
|
|
int i = 0;
|
|
|
|
for (auto & t : timers)
|
|
|
|
{
|
|
|
|
if (t.count != 0 || t.usedcounter != 0)
|
|
|
|
{
|
|
|
|
fprintf(prof,"job %3i calls %8li, time %6.4f sec",i,t.count,t.tottime); // NOLINT
|
|
|
|
if(t.flops != 0.0)
|
|
|
|
fprintf(prof,", MFlops = %6.2f",t.flops / (t.tottime) * 1e-6); // NOLINT
|
|
|
|
if(t.loads != 0.0)
|
|
|
|
fprintf(prof,", MLoads = %6.2f",t.loads / (t.tottime) * 1e-6); // NOLINT
|
|
|
|
if(t.stores != 0.0)
|
|
|
|
fprintf(prof,", MStores = %6.2f",t.stores / (t.tottime) * 1e-6); // NOLINT
|
|
|
|
if(t.usedcounter)
|
|
|
|
fprintf(prof," %s",t.name.c_str()); // NOLINT
|
|
|
|
fprintf(prof,"\n"); // NOLINT
|
|
|
|
}
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int NgProfiler :: CreateTimer (const std::string & name)
|
|
|
|
{
|
|
|
|
static std::mutex createtimer_mutex;
|
|
|
|
int nr = -1;
|
|
|
|
{
|
|
|
|
std::lock_guard<std::mutex> guard(createtimer_mutex);
|
|
|
|
for (int i = SIZE-1; i > 0; i--)
|
|
|
|
{
|
|
|
|
auto & t = timers[i];
|
|
|
|
if (!t.usedcounter)
|
|
|
|
{
|
|
|
|
t.usedcounter = 1;
|
|
|
|
t.name = name;
|
|
|
|
nr = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (nr > -1) return nr;
|
|
|
|
static bool first_overflow = true;
|
|
|
|
if (first_overflow)
|
|
|
|
{
|
|
|
|
first_overflow = false;
|
|
|
|
NgProfiler::logger->warn("no more timer available, reusing last one");
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void NgProfiler :: Reset ()
|
|
|
|
{
|
|
|
|
for(auto & t : timers)
|
|
|
|
{
|
|
|
|
t.tottime = 0.0;
|
|
|
|
t.count = 0;
|
|
|
|
t.flops = 0.0;
|
|
|
|
t.loads = 0;
|
|
|
|
t.stores = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
NgProfiler prof; // NOLINT
|
|
|
|
|
|
|
|
|
|
|
|
} // namespace ngcore
|