~ubuntu-branches/ubuntu/precise/boinc/precise

« back to all changes in this revision

Viewing changes to sched/credit_test.cpp

Tags: 6.12.8+dfsg-1
* New upstream release.
* Simplified debian/rules

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// credit_test
 
2
//
 
3
// Simulate the new credit system for the N most recent jobs
 
4
// in project's database, and give a comparison of new and old systems.
 
5
// Doesn't modify anything.
 
6
//
 
7
// You must first run html/ops/credit_test.php to create a data file
 
8
//
 
9
 
 
10
#include <stdio.h>
 
11
#include <string.h>
 
12
 
 
13
#include "sched_config.h"
 
14
#include "sched_customize.h"
 
15
#include "boinc_db.h"
 
16
 
 
17
#define MAX_JOBS 100000
 
18
#define COBBLESTONE_SCALE 100/86400e9
 
19
#define PRINT_AV_PERIOD 100
 
20
#define SCALE_AV_PERIOD 20
 
21
 
 
22
#define MIN_HOST_SAMPLES  10
 
23
    // don't use host scaling unless have this many samples for host
 
24
#define MIN_VERSION_SAMPLES   100
 
25
    // don't update a version's scale unless it has this many samples,
 
26
    // and don't accumulate stats until this occurs
 
27
 
 
28
#define HAV_AVG_THRESH  20
 
29
#define HAV_AVG_WEIGHT  .01
 
30
#define HAV_AVG_LIMIT   10
 
31
 
 
32
#define AV_AVG_THRESH   50000
 
33
#define AV_AVG_WEIGHT   .005
 
34
#define AV_AVG_LIMIT    10
 
35
 
 
36
double min_credit = 0;
 
37
vector<APP_VERSION> app_versions;
 
38
vector<APP> apps;
 
39
vector<HOST_APP_VERSION> host_app_versions;
 
40
vector<PLATFORM> platforms;
 
41
bool accumulate_stats = false;
 
42
    // set to true when we have PFC averages for
 
43
    // both a GPU and a CPU version
 
44
 
 
45
void read_db() {
 
46
    DB_APP app;
 
47
    DB_APP_VERSION av;
 
48
 
 
49
    while (!app.enumerate("")) {
 
50
        apps.push_back(app);
 
51
    }
 
52
    while (!av.enumerate("where deprecated=0 order by id desc")) {
 
53
        av.pfc_scale= 1;
 
54
        app_versions.push_back(av);
 
55
    }
 
56
    DB_PLATFORM platform;
 
57
    while (!platform.enumerate("")) {
 
58
        platforms.push_back(platform);
 
59
    }
 
60
}
 
61
 
 
62
PLATFORM* lookup_platform(int id) {
 
63
    unsigned int i;
 
64
    for (i=0; i<platforms.size(); i++) {
 
65
        PLATFORM& p = platforms[i];
 
66
        if (p.id == id) return &p;
 
67
    }
 
68
    return NULL;
 
69
}
 
70
 
 
71
APP_VERSION* lookup_av(int id) {
 
72
    unsigned int i;
 
73
    for (i=0; i<app_versions.size(); i++) {
 
74
        APP_VERSION& av = app_versions[i];
 
75
        if (av.id == id) return &av;
 
76
    }
 
77
    printf(" missing app version %d\n", id);
 
78
    exit(1);
 
79
}
 
80
 
 
81
APP& lookup_app(int id) {
 
82
    unsigned int i;
 
83
    for (i=0; i<apps.size(); i++) {
 
84
        APP& app = apps[i];
 
85
        if (app.id == id) return app;
 
86
    }
 
87
    printf("missing app: %d\n", id);
 
88
    exit(1);
 
89
    return apps[0];
 
90
}
 
91
 
 
92
HOST_APP_VERSION& lookup_host_app_version(int hostid, int avid) {
 
93
    unsigned int i;
 
94
    for (i=0; i<host_app_versions.size(); i++) {
 
95
        HOST_APP_VERSION& hav = host_app_versions[i];
 
96
        if (hav.host_id != hostid) continue;
 
97
        if (hav.app_version_id != avid) continue;
 
98
        return hav;
 
99
    }
 
100
    HOST_APP_VERSION h;
 
101
    h.host_id = hostid;
 
102
    h.app_version_id = avid;
 
103
    host_app_versions.push_back(h);
 
104
    return host_app_versions.back();
 
105
}
 
106
 
 
107
void print_average(AVERAGE& a) {
 
108
    printf("n %f avg %f\n", a.n, a.get_avg()
 
109
    );
 
110
}
 
111
 
 
112
void print_avs() {
 
113
    unsigned int i;
 
114
    printf("----- scales --------\n");
 
115
    for (i=0; i<app_versions.size(); i++) {
 
116
        APP_VERSION& av = app_versions[i];
 
117
        if (!av.pfc.n) continue;
 
118
        PLATFORM* p = lookup_platform(av.platformid);
 
119
        printf("app %d vers %d (%s %s)\n scale %f ",
 
120
            av.appid, av.id, p->name, av.plan_class, av.pfc_scale
 
121
        );
 
122
        print_average(av.pfc);
 
123
        printf("\n");
 
124
    }
 
125
    printf("-------------\n");
 
126
}
 
127
 
 
128
void lookup_host(DB_HOST& h, int id) {
 
129
    int retval = h.lookup_id(id);
 
130
    if (retval) {
 
131
        printf("can't find host %d\n", id);
 
132
        exit(1);
 
133
    }
 
134
}
 
135
 
 
136
// used in the computation of AV scale factors
 
137
//
 
138
struct RSC_INFO {
 
139
    double pfc_sum;
 
140
    double pfc_n;
 
141
    int nvers_thresh;   // # app versions w/ lots of samples
 
142
    int nvers_total;
 
143
 
 
144
    RSC_INFO() {
 
145
        pfc_sum = 0;
 
146
        pfc_n = 0;
 
147
        nvers_thresh = 0;
 
148
        nvers_total = 0;
 
149
    }
 
150
    void update(APP_VERSION& av) {
 
151
        nvers_total++;
 
152
        if (av.pfc.n > MIN_VERSION_SAMPLES) {
 
153
            nvers_thresh++;
 
154
            pfc_sum += av.pfc.get_avg() * av.pfc.n;
 
155
            pfc_n += av.pfc.n;
 
156
        }
 
157
    }
 
158
    double avg() {
 
159
        return pfc_sum/pfc_n;
 
160
    }
 
161
};
 
162
 
 
163
void scale_versions(APP& app, double avg) {
 
164
    for (unsigned int j=0; j<app_versions.size(); j++) {
 
165
        APP_VERSION& av = app_versions[j];
 
166
        if (av.appid != app.id) continue;
 
167
        if (av.pfc.n < MIN_VERSION_SAMPLES) continue;
 
168
 
 
169
        av.pfc_scale= avg/av.pfc.get_avg();
 
170
        PLATFORM* p = lookup_platform(av.platformid);
 
171
        printf("updating scale factor for (%s %s)\n",
 
172
             p->name, av.plan_class
 
173
        );
 
174
        printf(" n: %f avg PFC: %f new scale: %f\n",
 
175
            av.pfc.n, av.pfc.get_avg(), av.pfc_scale
 
176
        );
 
177
    }
 
178
    app.min_avg_pfc = avg;
 
179
}
 
180
 
 
181
// update app version scale factors,
 
182
// and find the min average PFC for each app
 
183
//
 
184
void update_av_scales() {
 
185
    unsigned int i, j;
 
186
    printf("----- updating scales --------\n");
 
187
    for (i=0; i<apps.size(); i++) {
 
188
        APP& app = apps[i];
 
189
        printf("app %d\n", app.id);
 
190
        RSC_INFO cpu_info, gpu_info;
 
191
 
 
192
        // find the average PFC of CPU and GPU versions
 
193
 
 
194
        for (j=0; j<app_versions.size(); j++) {
 
195
            APP_VERSION& av = app_versions[j];
 
196
            if (av.appid != app.id) continue;
 
197
            if (strstr(av.plan_class, "cuda") || strstr(av.plan_class, "ati")) {
 
198
                printf("gpu update: %d %s %f\n", av.id, av.plan_class, av.pfc.get_avg());
 
199
                gpu_info.update(av);
 
200
            } else {
 
201
                printf("cpu update: %d %s %f\n", av.id, av.plan_class, av.pfc.get_avg());
 
202
                cpu_info.update(av);
 
203
            }
 
204
        }
 
205
 
 
206
        // If there are only CPU or only GPU versions,
 
207
        // and 2 are above threshold, normalize to the average
 
208
        //
 
209
        // If there are both, and at least 1 of each is above threshold,
 
210
        // normalize to the min of the averages
 
211
        //
 
212
        if (cpu_info.nvers_total) {
 
213
            if (gpu_info.nvers_total) {
 
214
                if (cpu_info.nvers_thresh && gpu_info.nvers_thresh) {
 
215
                    printf("CPU avg: %f\n", cpu_info.avg());
 
216
                    printf("GPU avg: %f\n", gpu_info.avg());
 
217
                    scale_versions(app,
 
218
                        cpu_info.avg()<gpu_info.avg()?cpu_info.avg():gpu_info.avg()
 
219
                    );
 
220
                    accumulate_stats = true;
 
221
                }
 
222
            } else {
 
223
                if (cpu_info.nvers_thresh > 1) {
 
224
                    scale_versions(app, cpu_info.avg());
 
225
                    accumulate_stats = true;
 
226
                }
 
227
            }
 
228
        } else {
 
229
            if (gpu_info.nvers_thresh > 1) {
 
230
                scale_versions(app, gpu_info.avg());
 
231
                accumulate_stats = true;
 
232
            }
 
233
        }
 
234
 
 
235
 
 
236
    }
 
237
    printf("-------------\n");
 
238
}
 
239
 
 
240
// Compute or estimate normalized peak FLOP count (PFC),
 
241
// and update data structures.
 
242
// Return true if the PFC was computed in the "normal" way,
 
243
// i.e. not anon platform, and reflects version scaling
 
244
//
 
245
bool get_pfc(RESULT& r, WORKUNIT& wu, double& pfc) {
 
246
    APP_VERSION* avp = NULL;
 
247
    DB_HOST host;
 
248
 
 
249
    APP& app = lookup_app(r.appid);
 
250
    HOST_APP_VERSION& hav = lookup_host_app_version(
 
251
        r.hostid, r.app_version_id
 
252
    );
 
253
 
 
254
    if (r.elapsed_time) {
 
255
        // new client
 
256
        hav.et.update(
 
257
            r.elapsed_time/wu.rsc_fpops_est,
 
258
            HAV_AVG_THRESH, HAV_AVG_WEIGHT, HAV_AVG_LIMIT
 
259
        );
 
260
        if (r.app_version_id < 0) {
 
261
            // anon platform
 
262
            //
 
263
            pfc = app.min_avg_pfc;
 
264
            if (hav.et.n > MIN_HOST_SAMPLES) {
 
265
                pfc *= (r.elapsed_time/wu.rsc_fpops_est)/hav.et.get_avg();
 
266
            }
 
267
            printf("  skipping: anon platform\n");
 
268
            return false;
 
269
        } else {
 
270
            pfc = (r.elapsed_time * r.flops_estimate);
 
271
            avp = lookup_av(r.app_version_id);
 
272
            printf("  sec: %.0f GFLOPS: %.0f PFC: %.0fG raw credit: %.2f\n",
 
273
                r.elapsed_time, r.flops_estimate/1e9, pfc/1e9, pfc*COBBLESTONE_SCALE
 
274
            );
 
275
        }
 
276
    } else {
 
277
        // old client
 
278
        //
 
279
        hav.et.update(
 
280
            r.cpu_time/wu.rsc_fpops_est,
 
281
            HAV_AVG_THRESH, HAV_AVG_WEIGHT, HAV_AVG_LIMIT
 
282
        );
 
283
        pfc = app.min_avg_pfc*wu.rsc_fpops_est;
 
284
        if (hav.et.n > MIN_HOST_SAMPLES) {
 
285
            double s = r.elapsed_time/hav.et.get_avg();
 
286
            pfc *= s;
 
287
            printf("  old client: scaling by %f (%f/%f)\n",
 
288
                s, r.elapsed_time, hav.et.get_avg()
 
289
            );
 
290
        } else {
 
291
            printf("  old client: not scaling\n");
 
292
        }
 
293
        return false;
 
294
    }
 
295
 
 
296
    avp->pfc.update(
 
297
        pfc/wu.rsc_fpops_est,
 
298
        AV_AVG_THRESH, AV_AVG_WEIGHT, AV_AVG_LIMIT
 
299
    );
 
300
 
 
301
    // version normalization
 
302
 
 
303
    double vnpfc = pfc * avp->pfc_scale;
 
304
 
 
305
    PLATFORM* p = lookup_platform(avp->platformid);
 
306
    printf("  updated version PFC: %f\n", pfc/wu.rsc_fpops_est);
 
307
    printf("  version scale (%s %s): %f\n",
 
308
        p->name, avp->plan_class, avp->pfc_scale
 
309
    );
 
310
 
 
311
    // host normalization
 
312
 
 
313
    hav.pfc.update(
 
314
        pfc/wu.rsc_fpops_est,
 
315
        HAV_AVG_THRESH, HAV_AVG_WEIGHT, HAV_AVG_LIMIT
 
316
    );
 
317
 
 
318
    double host_scale = 1;
 
319
 
 
320
    if (hav.pfc.n > MIN_HOST_SAMPLES && avp->pfc.n > MIN_VERSION_SAMPLES) {
 
321
        host_scale = avp->pfc.get_avg()/hav.pfc.get_avg();
 
322
        if (host_scale > 1) host_scale = 1;
 
323
        printf("  host scale: %f (%f/%f)\n",
 
324
            host_scale, avp->pfc.get_avg(), hav.pfc.get_avg()
 
325
        );
 
326
    }
 
327
    pfc = vnpfc * host_scale;
 
328
 
 
329
    return avp->pfc.n > MIN_VERSION_SAMPLES;
 
330
}
 
331
 
 
332
int main(int argc, char** argv) {
 
333
    RESULT r;
 
334
    WORKUNIT wu;
 
335
    int retval;
 
336
    FILE* f = fopen("credit_test_unsorted", "w");
 
337
 
 
338
    if (argc > 1) {
 
339
        min_credit = atof(argv[1]);
 
340
    }
 
341
 
 
342
    retval = config.parse_file();
 
343
    if (retval) {printf("no config: %d\n", retval); exit(1);}
 
344
    retval = boinc_db.open(
 
345
        config.db_name, config.db_host, config.db_user, config.db_passwd
 
346
    );
 
347
    if (retval) {printf("no db\n"); exit(1);}
 
348
 
 
349
    read_db();
 
350
 
 
351
    int n=0, nstats=0;
 
352
    double total_old_credit = 0;
 
353
    double total_new_credit = 0;
 
354
    FILE* in = fopen("credit_test_data", "r");
 
355
    printf("min credit: %f\n", min_credit);
 
356
    while (!feof(in)) {
 
357
        int c = fscanf(in, "%d %d %d %d %lf %d %lf %lf %lf %lf",
 
358
            &r.id, &r.workunitid, &r.appid, &r.hostid,
 
359
            &r.claimed_credit, &r.app_version_id, &r.elapsed_time,
 
360
            &r.flops_estimate, &r.cpu_time, &wu.rsc_fpops_est
 
361
        );
 
362
        if (c != 10) break;
 
363
        printf("%d) result %d WU %d host %d old credit %f\n",
 
364
            n, r.id, r.workunitid, r.hostid, r.claimed_credit
 
365
        );
 
366
        n++;
 
367
        if (r.claimed_credit < min_credit) {
 
368
            printf("  skipping: small credit\n");
 
369
            continue;
 
370
        }
 
371
 
 
372
        double pfc;
 
373
        bool normal = get_pfc(r, wu, pfc);
 
374
        double new_claimed_credit = pfc * COBBLESTONE_SCALE;
 
375
        if (normal) {
 
376
            printf(" new credit %.2f old credit %.2f\n",
 
377
                new_claimed_credit, r.claimed_credit
 
378
            );
 
379
            if (accumulate_stats) {
 
380
                total_old_credit += r.claimed_credit;
 
381
                total_new_credit += new_claimed_credit;
 
382
                nstats++;
 
383
                fprintf(f, "%d %d %.2f %.2f\n",
 
384
                    r.workunitid, r.id, new_claimed_credit, r.claimed_credit
 
385
                );
 
386
            } else {
 
387
                printf("  not accumulated\n");
 
388
            }
 
389
        } else {
 
390
            printf(" new credit (average): %f\n", new_claimed_credit);
 
391
        }
 
392
 
 
393
        if (n%SCALE_AV_PERIOD ==0) {
 
394
            update_av_scales();
 
395
        }
 
396
        if (n%PRINT_AV_PERIOD ==0) {
 
397
            print_avs();
 
398
        }
 
399
        if (n%1000 == 0) {
 
400
            fprintf(stderr, "%d\n", n);
 
401
        }
 
402
        if (n >= MAX_JOBS) break;
 
403
    }
 
404
    fclose(f);
 
405
    if (nstats == 0) {
 
406
        printf("Insufficient jobs were read from DB\n");
 
407
        exit(0);
 
408
    }
 
409
 
 
410
    print_avs();
 
411
 
 
412
    printf("Average credit: old %.2f new %.2f (ratio %.2f)\n",
 
413
        total_old_credit/nstats, total_new_credit/nstats,
 
414
        total_new_credit/total_old_credit
 
415
    );
 
416
    //printf("Variance claimed to grant old credit: %f\n", sqrt(variance_old/nstats));
 
417
    //printf("Variance claimed to grant old credit: %f\n", sqrt(variance_old/nstats));
 
418
}