-
Notifications
You must be signed in to change notification settings - Fork 9
/
xsiostat.c
284 lines (250 loc) · 8.71 KB
/
xsiostat.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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
/*
* -----------------------------
* XenServer Storage I/O Stats
* -----------------------------
* xsiostat.c
* ------------
*
* Copyright (c) 2013, 2014 Citrix Systems Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; version 2.1 only. with the special
* exception on linking described in file LICENSE.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*/
// Header files
#define _GNU_SOURCE
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <sys/queue.h>
#include <sys/time.h>
#include "xsiostat.h"
// Helper functions
void
usage(char *argv0){
// Local variables
int i; // Temporary integer
// Print usage
for (i=0; i<XSIS_PROGNAME_LEN+2; i++) fprintf(stderr, "-");
fprintf(stderr, "\n %s\n", XSIS_PROGNAME);
for (i=0; i<XSIS_PROGNAME_LEN+2; i++) fprintf(stderr, "-");
fprintf(stderr, "\n");
fprintf(stderr, "Usage: %s [ -hs ] [ -i <interval> ] [ -o <out_file> ]" \
" [ -d <domain_id> [ ... ] ] [ -v <vbd_id> [ ... ] ]\n",
argv0);
fprintf(stderr, " -h Print this help message and quit.\n");
fprintf(stderr, " -s Scan for new VBDs at each iteration.\n");
fprintf(stderr, " -d Filter for DOM ID (run list_domains for" \
" a list).\n");
fprintf(stderr, " -v Filter for VBD ID (run xenstore-ls" \
" /local/domain/<dom_id>/device/vbd for a list).\n");
fprintf(stderr, " -i interval Interval between outputs in" \
" milliseconds (1000 = 1s, default=%d).\n", XSIS_INTERVAL);
fprintf(stderr, " -o out_file File to write the output to (in" \
" binary format).\n");
}
// Global variables
static uint32_t unit = 1000000; // MB/s
int PAGE_SIZE;
// Alarm handler
void
sigalarm_h(){
return;
}
// Main loop
static void
main_loop(xsis_vbds_t *vbds){
// Local variables
static struct timeval now_0; // Current time
static struct timeval now_1; // Time at last iteration
float now_diff; // now_0 and now_1 time diff (secs)
uint8_t header = 0; // Has the header been printed? (flag)
xsis_vbd_t *vbd; // Temporary vbd iterator
// Update time structures
memcpy(&now_1, &now_0, sizeof(now_1));
gettimeofday(&now_0, NULL);
now_diff = (float)(now_0.tv_sec-now_1.tv_sec);
now_diff += ((float)now_0.tv_usec)/1000000;
now_diff -= ((float)now_1.tv_usec)/1000000;
// Loop through VBDs
LIST_FOREACH(vbd, vbds, vbds){
// Update VBD statistics
if (vbd_update(vbd)){
vbd_delete(vbd, vbds);
continue;
}
// Print header
if (!header){
printf("----------------------------------------------------" \
"----------------------------------\n");
printf(" DOM VBD r/s w/s rMB/s wMB/s" \
" rAvgQs wAvgQs Low_Mem_Mode\n");
header = 1;
}
// Print general VBD info
printf("%5d,%5d: ", vbd->domid, vbd->vbdid);
// Print rw iops
printf("%10.2f ",
((float)(vbd->tdstat.rop_0-vbd->tdstat.rop_1))/now_diff);
printf("%10.2f ",
((float)(vbd->tdstat.wop_0-vbd->tdstat.wop_1))/now_diff);
// Print rw throughput
printf("%8.2f ",
(((float)(vbd->tdstat.rsc_0-vbd->tdstat.rsc_1)*XSIS_SECTOR_SZ)/
(float)unit)/now_diff);
printf("%8.2f ",
(((float)(vbd->tdstat.wsc_0-vbd->tdstat.wsc_1)*XSIS_SECTOR_SZ)/
(float)unit)/now_diff);
// Print average queue size
printf("%6.2f ",
((float)(vbd->tdstat.rtu_0-vbd->tdstat.rtu_1))/
(now_diff*1000000));
printf("%6.2f",
((float)(vbd->tdstat.wtu_0-vbd->tdstat.wtu_1))/
(now_diff*1000000));
printf("%6d",vbd->tdstat.low_mem_mode);
// Break line
printf("\n");
}
// Flush if anything was printed
if (header){
printf("\n");
fflush(stdout);
}
// Return
return;
}
// Main
int
main(int argc, char **argv) {
// Local variables
xsis_flts_t domids; // List of DOM IDs to filter
xsis_flts_t vbdids; // List of VBD IDs to filter
xsis_vbds_t vbds; // List of attached VBDs
int32_t inter = -1; // Report interval (ms)
uint8_t scan = 0; // Scan for new VBDs (flag)
uint8_t reporting = 1; // Currently reporting (flag)
struct itimerval itv; // itimer setup
char *datafn = NULL; // Datafile pathname
FILE *datafp = NULL; // Datafile file pointer
uint32_t filter; // Temporary filter
int i; // Temporary integer
int err = 0; // Return value
// Initialise
PAGE_SIZE = sysconf(_SC_PAGESIZE);
LIST_INIT(&domids);
LIST_INIT(&vbdids);
LIST_INIT(&vbds);
// Fetch arguments
while ((i = getopt(argc, argv, "hsd:v:i:o:")) != -1){
switch (i){
case 's': // Set scan flag, if unset
if (scan){
fprintf(stderr, "%s: Invalid argument \"-s\", scan flag" \
" already set.\n", argv[0]);
goto err;
}
scan++;
break;
case 'd': // Add DOM ID to filter
filter = (uint32_t)strtoul(optarg, NULL, 10);
if (flt_add(&domids, filter))
goto err;
break;
case 'v': // Add VBD ID to filter
filter = (uint32_t)strtoul(optarg, NULL, 10);
if (flt_add(&vbdids, filter))
goto err;
break;
case 'i': // Set output intervals, if unset
if (inter != -1){
fprintf(stderr, "%s: Invalid argument \"-i\", output" \
" interval already set.\n", argv[0]);
goto err;
}
inter = (int32_t)strtoul(optarg, NULL, 10);
break;
case 'o': // Set datafile name
if (datafn != NULL){
fprintf(stderr, "%s: Invalid argument \"-o\", output"\
" datafile already set.\n", argv[0]);
goto err;
}
if (!(datafn = strdup(optarg))){
perror("strdup");
fprintf(stderr, "%s: Error allocating memory for datafile" \
" name.\n", argv[0]);
goto err;
}
break;
case 'h': // Print help
default:
usage(argv[0]);
goto out;
}
}
// Validate parameters and set defaults
if (inter < 0)
inter = XSIS_INTERVAL;
if ((datafn != NULL) && (!(datafp = fopen(datafn, "w")))){
perror("fopen");
fprintf(stderr, "%s: Error opening datafile '%s' for writing.\n",
argv[0], datafn);
goto err;
}
// Allocate initial set of VBDs
if (vbds_alloc(&vbds, &domids, &vbdids))
goto err;
// Set alarm
signal(SIGALRM, sigalarm_h);
itv.it_interval.tv_sec = inter/1000;
itv.it_interval.tv_usec = (inter%1000)*1000;
itv.it_value.tv_sec = 0;
itv.it_value.tv_usec = 100000;
setitimer(ITIMER_REAL, &itv, NULL);
// Loop
while(!err){
// Wait for alarm
pause();
// Update attached VBDs
if (scan)
err = vbds_alloc(&vbds, &domids, &vbdids);
else
if (LIST_EMPTY(&vbds)){
// There are no VBDs to report and we are not scanning
fprintf(stderr, "No VBDs to report and 'scan' flag not set.\n");
break;
}
// Report
if (!LIST_EMPTY(&vbds)){
reporting = 1;
main_loop(&vbds);
} else if (reporting){
printf("Waiting for VBDs to be plugged.\n");
reporting = 0;
}
}
out:
// Release resources
vbds_free(&vbds);
flts_free(&domids);
flts_free(&vbdids);
if (datafn)
free(datafn);
if (datafp)
fclose(datafp);
// Return
return(err);
err:
err = 1;
goto out;
}