You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
287 lines
8.9 KiB
287 lines
8.9 KiB
/*
|
|
* Copyright 2011-2016 Formal Methods and Tools, University of Twente
|
|
* Copyright 2016-2017 Tom van Dijk, Johannes Kepler University Linz
|
|
*
|
|
* 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 <sylvan_int.h>
|
|
|
|
#include <errno.h> // for errno
|
|
#include <string.h> // memset
|
|
#include <sys/mman.h>
|
|
#include <inttypes.h>
|
|
|
|
#if SYLVAN_STATS
|
|
|
|
#ifdef __ELF__
|
|
__thread sylvan_stats_t sylvan_stats;
|
|
#else
|
|
pthread_key_t sylvan_stats_key;
|
|
#endif
|
|
|
|
/**
|
|
* Instructions for sylvan_stats_report
|
|
*/
|
|
struct
|
|
{
|
|
int type; /* 0 for print line, 1 for simple counter, 2 for operation with CACHED and CACHEDPUT */
|
|
/* 3 for timer, 4 for report table data */
|
|
int id;
|
|
const char *key;
|
|
} sylvan_report_info[] =
|
|
{
|
|
{0, 0, "Tables"},
|
|
{1, BDD_NODES_CREATED, "MTBDD nodes created"},
|
|
{1, BDD_NODES_REUSED, "MTBDD nodes reused"},
|
|
{1, LDD_NODES_CREATED, "LDD nodes created"},
|
|
{1, LDD_NODES_REUSED, "LDD nodes reused"},
|
|
{1, LLMSSET_LOOKUP, "Lookup iterations"},
|
|
{4, 0, NULL}, /* trigger to report unique nodes and operation cache */
|
|
|
|
{0, 0, "Operation Count Cache get Cache put"},
|
|
{2, BDD_AND, "BDD and"},
|
|
{2, BDD_XOR, "BDD xor"},
|
|
{2, BDD_ITE, "BDD ite"},
|
|
{2, BDD_EXISTS, "BDD exists"},
|
|
{2, BDD_PROJECT, "BDD project"},
|
|
{2, BDD_AND_EXISTS, "BDD andexists"},
|
|
{2, BDD_AND_PROJECT, "BDD andproject"},
|
|
{2, BDD_RELNEXT, "BDD relnext"},
|
|
{2, BDD_RELPREV, "BDD relprev"},
|
|
{2, BDD_CLOSURE, "BDD closure"},
|
|
{2, BDD_COMPOSE, "BDD compose"},
|
|
{2, BDD_RESTRICT, "BDD restrict"},
|
|
{2, BDD_CONSTRAIN, "BDD constrain"},
|
|
{2, BDD_SUPPORT, "BDD support"},
|
|
{2, BDD_SATCOUNT, "BDD satcount"},
|
|
{2, BDD_PATHCOUNT, "BDD pathcount"},
|
|
{2, BDD_ISBDD, "BDD isbdd"},
|
|
|
|
{2, MTBDD_APPLY, "MTBDD binary apply"},
|
|
{2, MTBDD_UAPPLY, "MTBDD unary apply"},
|
|
{2, MTBDD_ABSTRACT, "MTBDD abstract"},
|
|
{2, MTBDD_ITE, "MTBDD ite"},
|
|
{2, MTBDD_EQUAL_NORM, "MTBDD eq norm"},
|
|
{2, MTBDD_EQUAL_NORM_REL, "MTBDD eq norm rel"},
|
|
{2, MTBDD_LEQ, "MTBDD leq"},
|
|
{2, MTBDD_LESS, "MTBDD less"},
|
|
{2, MTBDD_GEQ, "MTBDD geq"},
|
|
{2, MTBDD_GREATER, "MTBDD greater"},
|
|
{2, MTBDD_AND_ABSTRACT_PLUS, "MTBDD and_abs_plus"},
|
|
{2, MTBDD_AND_ABSTRACT_MAX, "MTBDD and_abs_max"},
|
|
{2, MTBDD_COMPOSE, "MTBDD compose"},
|
|
{2, MTBDD_MINIMUM, "MTBDD minimum"},
|
|
{2, MTBDD_MAXIMUM, "MTBDD maximum"},
|
|
{2, MTBDD_EVAL_COMPOSE, "MTBDD eval_compose"},
|
|
|
|
{2, LDD_UNION, "LDD union"},
|
|
{2, LDD_MINUS, "LDD minus"},
|
|
{2, LDD_INTERSECT, "LDD intersect"},
|
|
{2, LDD_RELPROD, "LDD relprod"},
|
|
{2, LDD_RELPREV, "LDD relprev"},
|
|
{2, LDD_PROJECT, "LDD project"},
|
|
{2, LDD_JOIN, "LDD join"},
|
|
{2, LDD_MATCH, "LDD match"},
|
|
{2, LDD_SATCOUNT, "LDD satcount"},
|
|
{2, LDD_SATCOUNTL, "LDD satcountl"},
|
|
{2, LDD_ZIP, "LDD zip"},
|
|
{2, LDD_RELPROD_UNION, "LDD relprod_union"},
|
|
{2, LDD_PROJECT_MINUS, "LDD project_minus"},
|
|
|
|
{0, 0, "Garbage collection"},
|
|
{1, SYLVAN_GC_COUNT, "GC executions"},
|
|
{3, SYLVAN_GC, "Total time spent"},
|
|
|
|
{-1, -1, NULL},
|
|
};
|
|
|
|
VOID_TASK_0(sylvan_stats_reset_perthread)
|
|
{
|
|
#ifdef __ELF__
|
|
for (int i=0; i<SYLVAN_COUNTER_COUNTER; i++) {
|
|
sylvan_stats.counters[i] = 0;
|
|
}
|
|
for (int i=0; i<SYLVAN_TIMER_COUNTER; i++) {
|
|
sylvan_stats.timers[i] = 0;
|
|
}
|
|
#else
|
|
sylvan_stats_t *sylvan_stats = pthread_getspecific(sylvan_stats_key);
|
|
if (sylvan_stats == NULL) {
|
|
sylvan_stats = mmap(0, sizeof(sylvan_stats_t), PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
|
|
if (sylvan_stats == (sylvan_stats_t *)-1) {
|
|
fprintf(stderr, "sylvan_stats: Unable to allocate memory: %s!\n", strerror(errno));
|
|
exit(1);
|
|
}
|
|
}
|
|
pthread_setspecific(sylvan_stats_key, sylvan_stats);
|
|
for (int i=0; i<SYLVAN_COUNTER_COUNTER; i++) {
|
|
sylvan_stats->counters[i] = 0;
|
|
}
|
|
for (int i=0; i<SYLVAN_TIMER_COUNTER; i++) {
|
|
sylvan_stats->timers[i] = 0;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
VOID_TASK_IMPL_0(sylvan_stats_init)
|
|
{
|
|
#ifndef __ELF__
|
|
pthread_key_create(&sylvan_stats_key, NULL);
|
|
#endif
|
|
TOGETHER(sylvan_stats_reset_perthread);
|
|
}
|
|
|
|
/**
|
|
* Reset all counters (for statistics)
|
|
*/
|
|
VOID_TASK_IMPL_0(sylvan_stats_reset)
|
|
{
|
|
TOGETHER(sylvan_stats_reset_perthread);
|
|
}
|
|
|
|
VOID_TASK_1(sylvan_stats_sum, sylvan_stats_t*, target)
|
|
{
|
|
#ifdef __ELF__
|
|
for (int i=0; i<SYLVAN_COUNTER_COUNTER; i++) {
|
|
__sync_fetch_and_add(&target->counters[i], sylvan_stats.counters[i]);
|
|
}
|
|
for (int i=0; i<SYLVAN_TIMER_COUNTER; i++) {
|
|
__sync_fetch_and_add(&target->timers[i], sylvan_stats.timers[i]);
|
|
}
|
|
#else
|
|
sylvan_stats_t *sylvan_stats = pthread_getspecific(sylvan_stats_key);
|
|
if (sylvan_stats != NULL) {
|
|
for (int i=0; i<SYLVAN_COUNTER_COUNTER; i++) {
|
|
__sync_fetch_and_add(&target->counters[i], sylvan_stats->counters[i]);
|
|
}
|
|
for (int i=0; i<SYLVAN_TIMER_COUNTER; i++) {
|
|
__sync_fetch_and_add(&target->timers[i], sylvan_stats->timers[i]);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
VOID_TASK_IMPL_1(sylvan_stats_snapshot, sylvan_stats_t*, target)
|
|
{
|
|
memset(target, 0, sizeof(sylvan_stats_t));
|
|
TOGETHER(sylvan_stats_sum, target);
|
|
}
|
|
|
|
#define BLACK "\33[22;30m"
|
|
#define GRAY "\33[1;30m"
|
|
#define RED "\33[22;31m"
|
|
#define LRED "\33[1;31m"
|
|
#define GREEN "\33[22;32m"
|
|
#define LGREEN "\33[1;32m"
|
|
#define BROWN "\33[22;33m"
|
|
#define YELLOW "\33[1;33m"
|
|
#define BLUE "\33[22;34m"
|
|
#define LBLUE "\33[1;34m"
|
|
#define MAGENTA "\33[22;35m"
|
|
#define LMAGENTA "\33[1;35m"
|
|
#define CYAN "\33[22;36m"
|
|
#define LCYAN "\33[1;36m"
|
|
#define LGRAY "\33[22;37m"
|
|
#define WHITE "\33[1;37m"
|
|
#define NC "\33[m"
|
|
#define BOLD "\33[1m"
|
|
#define ULINE "\33[4m"
|
|
#define PINK "\33[38;5;200m"
|
|
|
|
static char*
|
|
to_h(double size, char *buf)
|
|
{
|
|
const char* units[] = {"B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"};
|
|
int i = 0;
|
|
for (;size>1024;size/=1024) i++;
|
|
sprintf(buf, "%.*f %s", i, size, units[i]);
|
|
return buf;
|
|
}
|
|
|
|
void
|
|
sylvan_stats_report(FILE *target)
|
|
{
|
|
LACE_ME;
|
|
sylvan_stats_t totals;
|
|
sylvan_stats_snapshot(&totals);
|
|
|
|
// fix timers for MACH
|
|
#ifdef __MACH__
|
|
mach_timebase_info_data_t timebase;
|
|
mach_timebase_info(&timebase);
|
|
uint64_t c = timebase.numer/timebase.denom;
|
|
for (int i=0;i<SYLVAN_TIMER_COUNTER;i++) totals.timers[i]*=c;
|
|
#endif
|
|
|
|
int color = isatty(fileno(target)) ? 1 : 0;
|
|
if (color) fprintf(target, ULINE WHITE "Sylvan statistics\n" NC);
|
|
else fprintf(target, "Sylvan statistics\n");
|
|
|
|
int i=0;
|
|
for (;;) {
|
|
if (sylvan_report_info[i].id == -1) break;
|
|
int id = sylvan_report_info[i].id;
|
|
int type = sylvan_report_info[i].type;
|
|
if (type == 0) {
|
|
if (color) fprintf(target, WHITE "\n%s\n" NC, sylvan_report_info[i].key);
|
|
else fprintf(target, "\n%s\n", sylvan_report_info[i].key);
|
|
} else if (type == 1) {
|
|
if (totals.counters[id] > 0) {
|
|
fprintf(target, "%-20s %'-16"PRIu64"\n", sylvan_report_info[i].key, totals.counters[id]);
|
|
}
|
|
} else if (type == 2) {
|
|
if (totals.counters[id] > 0) {
|
|
fprintf(target, "%-20s %'-16"PRIu64 " %'-16"PRIu64" %'-16"PRIu64 "\n", sylvan_report_info[i].key, totals.counters[id], totals.counters[id+1], totals.counters[id+2]);
|
|
}
|
|
} else if (type == 3) {
|
|
if (totals.timers[id] > 0) {
|
|
fprintf(target, "%-20s %'.6Lf sec.\n", sylvan_report_info[i].key, (long double)totals.timers[id]/1000000000);
|
|
}
|
|
} else if (type == 4) {
|
|
fprintf(target, "%-20s %'zu of %'zu buckets filled.\n", "Unique nodes table", llmsset_count_marked(nodes), llmsset_get_size(nodes));
|
|
fprintf(target, "%-20s %'zu of %'zu buckets filled.\n", "Operation cache", cache_getused(), cache_getsize());
|
|
char buf[64], buf2[64];
|
|
to_h(24ULL * llmsset_get_size(nodes), buf);
|
|
to_h(24ULL * llmsset_get_max_size(nodes), buf2);
|
|
fprintf(target, "%-20s %s (max real) of %s (allocated virtual memory).\n", "Memory (nodes)", buf, buf2);
|
|
to_h(36ULL * cache_getsize(), buf);
|
|
to_h(36ULL * cache_getmaxsize(), buf2);
|
|
fprintf(target, "%-20s %s (max real) of %s (allocated virtual memory).\n", "Memory (cache)", buf, buf2);
|
|
}
|
|
i++;
|
|
}
|
|
}
|
|
|
|
#else
|
|
|
|
VOID_TASK_IMPL_0(sylvan_stats_init)
|
|
{
|
|
}
|
|
|
|
VOID_TASK_IMPL_0(sylvan_stats_reset)
|
|
{
|
|
}
|
|
|
|
VOID_TASK_IMPL_1(sylvan_stats_snapshot, sylvan_stats_t*, target)
|
|
{
|
|
memset(target, 0, sizeof(sylvan_stats_t));
|
|
}
|
|
|
|
void
|
|
sylvan_stats_report(FILE* target)
|
|
{
|
|
(void)target;
|
|
}
|
|
|
|
#endif
|