mirror of
https://github.com/checkpoint-restore/criu
synced 2025-08-22 09:58:09 +00:00
crtools.h is too heavy to be included in many sources Signed-off-by: Andrey Vagin <avagin@openvz.org> Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
153 lines
3.3 KiB
C
153 lines
3.3 KiB
C
#include <unistd.h>
|
|
#include <sys/time.h>
|
|
#include "asm/atomic.h"
|
|
#include "protobuf.h"
|
|
#include "stats.h"
|
|
#include "image.h"
|
|
#include "protobuf/stats.pb-c.h"
|
|
|
|
struct timing {
|
|
struct timeval start;
|
|
struct timeval total;
|
|
};
|
|
|
|
struct dump_stats {
|
|
struct timing timings[DUMP_TIME_NR_STATS];
|
|
unsigned long counts[DUMP_CNT_NR_STATS];
|
|
};
|
|
|
|
struct restore_stats {
|
|
struct timing timings[RESTORE_TIME_NS_STATS];
|
|
atomic_t counts[RESTORE_CNT_NR_STATS];
|
|
};
|
|
|
|
struct dump_stats *dstats;
|
|
struct restore_stats *rstats;
|
|
|
|
void cnt_add(int c, unsigned long val)
|
|
{
|
|
if (dstats != NULL) {
|
|
BUG_ON(c >= DUMP_CNT_NR_STATS);
|
|
dstats->counts[c] += val;
|
|
} else if (rstats != NULL) {
|
|
BUG_ON(c >= RESTORE_CNT_NR_STATS);
|
|
atomic_add(val, &rstats->counts[c]);
|
|
} else
|
|
BUG();
|
|
}
|
|
|
|
static void timeval_accumulate(const struct timeval *from, const struct timeval *to,
|
|
struct timeval *res)
|
|
{
|
|
suseconds_t usec;
|
|
|
|
res->tv_sec += to->tv_sec - from->tv_sec;
|
|
usec = to->tv_usec;
|
|
if (usec < from->tv_usec) {
|
|
usec += USEC_PER_SEC;
|
|
res->tv_sec -= 1;
|
|
}
|
|
res->tv_usec += usec - from->tv_usec;
|
|
if (res->tv_usec > USEC_PER_SEC) {
|
|
res->tv_usec -= USEC_PER_SEC;
|
|
res->tv_sec += 1;
|
|
}
|
|
}
|
|
|
|
static struct timing *get_timing(int t)
|
|
{
|
|
if (dstats != NULL) {
|
|
BUG_ON(t >= DUMP_TIME_NR_STATS);
|
|
return &dstats->timings[t];
|
|
} else if (rstats != NULL) {
|
|
/*
|
|
* FIXME -- this does _NOT_ work when called
|
|
* from different tasks.
|
|
*/
|
|
BUG_ON(t >= RESTORE_TIME_NS_STATS);
|
|
return &rstats->timings[t];
|
|
}
|
|
|
|
BUG();
|
|
return NULL;
|
|
}
|
|
|
|
void timing_start(int t)
|
|
{
|
|
struct timing *tm;
|
|
|
|
tm = get_timing(t);
|
|
gettimeofday(&tm->start, NULL);
|
|
}
|
|
|
|
void timing_stop(int t)
|
|
{
|
|
struct timing *tm;
|
|
struct timeval now;
|
|
|
|
tm = get_timing(t);
|
|
gettimeofday(&now, NULL);
|
|
timeval_accumulate(&tm->start, &now, &tm->total);
|
|
}
|
|
|
|
static void encode_time(int t, u_int32_t *to)
|
|
{
|
|
struct timing *tm;
|
|
|
|
tm = get_timing(t);
|
|
*to = tm->total.tv_sec * USEC_PER_SEC + tm->total.tv_usec;
|
|
}
|
|
|
|
void write_stats(int what)
|
|
{
|
|
StatsEntry stats = STATS_ENTRY__INIT;
|
|
DumpStatsEntry ds_entry = DUMP_STATS_ENTRY__INIT;
|
|
RestoreStatsEntry rs_entry = RESTORE_STATS_ENTRY__INIT;
|
|
char *name;
|
|
int fd;
|
|
|
|
pr_info("Writing stats\n");
|
|
if (what == DUMP_STATS) {
|
|
stats.dump = &ds_entry;
|
|
|
|
encode_time(TIME_FREEZING, &ds_entry.freezing_time);
|
|
encode_time(TIME_FROZEN, &ds_entry.frozen_time);
|
|
encode_time(TIME_MEMDUMP, &ds_entry.memdump_time);
|
|
encode_time(TIME_MEMWRITE, &ds_entry.memwrite_time);
|
|
|
|
ds_entry.pages_scanned = dstats->counts[CNT_PAGES_SCANNED];
|
|
ds_entry.pages_skipped_parent = dstats->counts[CNT_PAGES_SKIPPED_PARENT];
|
|
ds_entry.pages_written = dstats->counts[CNT_PAGES_WRITTEN];
|
|
|
|
name = "dump";
|
|
} else if (what == RESTORE_STATS) {
|
|
stats.restore = &rs_entry;
|
|
|
|
rs_entry.pages_compared = atomic_read(&rstats->counts[CNT_PAGES_COMPARED]);
|
|
rs_entry.pages_skipped_cow = atomic_read(&rstats->counts[CNT_PAGES_SKIPPED_COW]);
|
|
|
|
encode_time(TIME_FORK, &rs_entry.forking_time);
|
|
encode_time(TIME_RESTORE, &rs_entry.restore_time);
|
|
|
|
name = "restore";
|
|
} else
|
|
return;
|
|
|
|
fd = open_image(CR_FD_STATS, O_DUMP, name);
|
|
if (fd >= 0) {
|
|
pb_write_one(fd, &stats, PB_STATS);
|
|
close(fd);
|
|
}
|
|
}
|
|
|
|
int init_stats(int what)
|
|
{
|
|
if (what == DUMP_STATS) {
|
|
dstats = xmalloc(sizeof(*dstats));
|
|
return dstats ? 0 : -1;
|
|
}
|
|
|
|
rstats = shmalloc(sizeof(struct restore_stats));
|
|
return rstats ? 0 : -1;
|
|
}
|