forked from checkpoint-restore/criu
-
Notifications
You must be signed in to change notification settings - Fork 0
/
stats.c
153 lines (127 loc) · 3.29 KB
/
stats.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
#include <unistd.h>
#include <fcntl.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_at(AT_FDCWD, 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;
}