Branch data Line data Source code
1 : : #include <unistd.h>
2 : : #include <fcntl.h>
3 : : #include <sys/time.h>
4 : : #include "asm/atomic.h"
5 : : #include "protobuf.h"
6 : : #include "stats.h"
7 : : #include "image.h"
8 : : #include "protobuf/stats.pb-c.h"
9 : :
10 : : struct timing {
11 : : struct timeval start;
12 : : struct timeval total;
13 : : };
14 : :
15 : : struct dump_stats {
16 : : struct timing timings[DUMP_TIME_NR_STATS];
17 : : unsigned long counts[DUMP_CNT_NR_STATS];
18 : : };
19 : :
20 : : struct restore_stats {
21 : : struct timing timings[RESTORE_TIME_NS_STATS];
22 : : atomic_t counts[RESTORE_CNT_NR_STATS];
23 : : };
24 : :
25 : : struct dump_stats *dstats;
26 : : struct restore_stats *rstats;
27 : :
28 : 455619 : void cnt_add(int c, unsigned long val)
29 : : {
30 [ + + ]: 455619 : if (dstats != NULL) {
31 [ - + ]: 454200 : BUG_ON(c >= DUMP_CNT_NR_STATS);
32 : 454200 : dstats->counts[c] += val;
33 [ + - ]: 1419 : } else if (rstats != NULL) {
34 [ - + ]: 1419 : BUG_ON(c >= RESTORE_CNT_NR_STATS);
35 : 1419 : atomic_add(val, &rstats->counts[c]);
36 : : } else
37 : 0 : BUG();
38 : 455619 : }
39 : :
40 : 11808 : static void timeval_accumulate(const struct timeval *from, const struct timeval *to,
41 : : struct timeval *res)
42 : : {
43 : : suseconds_t usec;
44 : :
45 : 11808 : res->tv_sec += to->tv_sec - from->tv_sec;
46 : 11808 : usec = to->tv_usec;
47 [ + + ]: 11808 : if (usec < from->tv_usec) {
48 : 109 : usec += USEC_PER_SEC;
49 : 109 : res->tv_sec -= 1;
50 : : }
51 : 11808 : res->tv_usec += usec - from->tv_usec;
52 [ - + ]: 11808 : if (res->tv_usec > USEC_PER_SEC) {
53 : 0 : res->tv_usec -= USEC_PER_SEC;
54 : 0 : res->tv_sec += 1;
55 : : }
56 : 11808 : }
57 : :
58 : 34037 : static struct timing *get_timing(int t)
59 : : {
60 [ + + ]: 34037 : if (dstats != NULL) {
61 [ - + ]: 30784 : BUG_ON(t >= DUMP_TIME_NR_STATS);
62 : 30784 : return &dstats->timings[t];
63 [ + - ]: 3253 : } else if (rstats != NULL) {
64 : : /*
65 : : * FIXME -- this does _NOT_ work when called
66 : : * from different tasks.
67 : : */
68 [ - + ]: 3253 : BUG_ON(t >= RESTORE_TIME_NS_STATS);
69 : 3253 : return &rstats->timings[t];
70 : : }
71 : :
72 : 0 : BUG();
73 : 0 : return NULL;
74 : : }
75 : :
76 : 12373 : void timing_start(int t)
77 : : {
78 : : struct timing *tm;
79 : :
80 : 12373 : tm = get_timing(t);
81 : 12373 : gettimeofday(&tm->start, NULL);
82 : 12373 : }
83 : :
84 : 11808 : void timing_stop(int t)
85 : : {
86 : : struct timing *tm;
87 : : struct timeval now;
88 : :
89 : 11808 : tm = get_timing(t);
90 : 11808 : gettimeofday(&now, NULL);
91 : 11808 : timeval_accumulate(&tm->start, &now, &tm->total);
92 : 11808 : }
93 : :
94 : : static void encode_time(int t, u_int32_t *to)
95 : : {
96 : : struct timing *tm;
97 : :
98 : 2240 : tm = get_timing(t);
99 : 448 : *to = tm->total.tv_sec * USEC_PER_SEC + tm->total.tv_usec;
100 : : }
101 : :
102 : 2240 : void write_stats(int what)
103 : : {
104 : 2240 : StatsEntry stats = STATS_ENTRY__INIT;
105 : 2240 : DumpStatsEntry ds_entry = DUMP_STATS_ENTRY__INIT;
106 : 2240 : RestoreStatsEntry rs_entry = RESTORE_STATS_ENTRY__INIT;
107 : : char *name;
108 : : int fd;
109 : :
110 : 2240 : pr_info("Writing stats\n");
111 [ + + ]: 2240 : if (what == DUMP_STATS) {
112 : 1792 : stats.dump = &ds_entry;
113 : :
114 : : encode_time(TIME_FREEZING, &ds_entry.freezing_time);
115 : : encode_time(TIME_FROZEN, &ds_entry.frozen_time);
116 : : encode_time(TIME_MEMDUMP, &ds_entry.memdump_time);
117 : : encode_time(TIME_MEMWRITE, &ds_entry.memwrite_time);
118 : 1792 : ds_entry.has_irmap_resolve = true;
119 : : encode_time(TIME_IRMAP_RESOLVE, &ds_entry.irmap_resolve);
120 : :
121 : 1792 : ds_entry.pages_scanned = dstats->counts[CNT_PAGES_SCANNED];
122 : 1792 : ds_entry.pages_skipped_parent = dstats->counts[CNT_PAGES_SKIPPED_PARENT];
123 : 1792 : ds_entry.pages_written = dstats->counts[CNT_PAGES_WRITTEN];
124 : :
125 : : name = "dump";
126 [ + - ]: 448 : } else if (what == RESTORE_STATS) {
127 : 448 : stats.restore = &rs_entry;
128 : :
129 : 896 : rs_entry.pages_compared = atomic_read(&rstats->counts[CNT_PAGES_COMPARED]);
130 : 448 : rs_entry.pages_skipped_cow = atomic_read(&rstats->counts[CNT_PAGES_SKIPPED_COW]);
131 : 448 : rs_entry.has_pages_restored = true;
132 : 448 : rs_entry.pages_restored = atomic_read(&rstats->counts[CNT_PAGES_RESTORED]);
133 : :
134 : : encode_time(TIME_FORK, &rs_entry.forking_time);
135 : : encode_time(TIME_RESTORE, &rs_entry.restore_time);
136 : :
137 : : name = "restore";
138 : : } else
139 : 0 : return;
140 : :
141 : 2240 : fd = open_image_at(AT_FDCWD, CR_FD_STATS, O_DUMP, name);
142 [ + - ]: 2240 : if (fd >= 0) {
143 : 2240 : pb_write_one(fd, &stats, PB_STATS);
144 : 2240 : close(fd);
145 : : }
146 : : }
147 : :
148 : 2805 : int init_stats(int what)
149 : : {
150 [ + + ]: 2805 : if (what == DUMP_STATS) {
151 [ - + ]: 1792 : dstats = xmalloc(sizeof(*dstats));
152 [ - + ]: 1792 : return dstats ? 0 : -1;
153 : : }
154 : :
155 : 1013 : rstats = shmalloc(sizeof(struct restore_stats));
156 [ - + ]: 1013 : return rstats ? 0 : -1;
157 : : }
|