This file is indexed.

/usr/share/doc/root/test/stressInterpreter.cxx is in root-system-doc 5.34.30-0ubuntu8.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  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
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
// @(#)root/test:$Id$
// Author: Axel Naumann, 2011-01-11

/////////////////////////////////////////////////////////////////
//
// Stress test (functionality and timing) for C++ interpreter.
//
/////////////////////////////////////////////////////////////////

#include <stdlib.h>
#include <iostream>
#include <fstream>
#include <vector>
#include <string>

#include "TSystem.h"
#include "TBenchmark.h"
#include "TInterpreter.h"
#include "TROOT.h"
#include "TApplication.h"

/////////////////////////////////////////////////////////////////
// Utility classes / functions

class Base {};

class Klass: public Base {
public:
   Klass() { fKlass = this; }
   ~Klass() { fKlass = 0; }
   Klass* get() const { return fKlass; }
   static const int first_klf = 30;
   static const int last_klf = 130;
   long f30(double d) const {return (long)(d + 30);}
   long f31(double d) const {return (long)(d + 31);}
   long f32(double d) const {return (long)(d + 32);}
   long f33(double d) const {return (long)(d + 33);}
   long f34(double d) const {return (long)(d + 34);}
   long f35(double d) const {return (long)(d + 35);}
   long f36(double d) const {return (long)(d + 36);}
   long f37(double d) const {return (long)(d + 37);}
   long f38(double d) const {return (long)(d + 38);}
   long f39(double d) const {return (long)(d + 39);}
   long f40(double d) const {return (long)(d + 40);}
   long f41(double d) const {return (long)(d + 41);}
   long f42(double d) const {return (long)(d + 42);}
   long f43(double d) const {return (long)(d + 43);}
   long f44(double d) const {return (long)(d + 44);}
   long f45(double d) const {return (long)(d + 45);}
   long f46(double d) const {return (long)(d + 46);}
   long f47(double d) const {return (long)(d + 47);}
   long f48(double d) const {return (long)(d + 48);}
   long f49(double d) const {return (long)(d + 49);}
   long f50(double d) const {return (long)(d + 50);}
   long f51(double d) const {return (long)(d + 51);}
   long f52(double d) const {return (long)(d + 52);}
   long f53(double d) const {return (long)(d + 53);}
   long f54(double d) const {return (long)(d + 54);}
   long f55(double d) const {return (long)(d + 55);}
   long f56(double d) const {return (long)(d + 56);}
   long f57(double d) const {return (long)(d + 57);}
   long f58(double d) const {return (long)(d + 58);}
   long f59(double d) const {return (long)(d + 59);}
   long f60(double d) const {return (long)(d + 60);}
   long f61(double d) const {return (long)(d + 61);}
   long f62(double d) const {return (long)(d + 62);}
   long f63(double d) const {return (long)(d + 63);}
   long f64(double d) const {return (long)(d + 64);}
   long f65(double d) const {return (long)(d + 65);}
   long f66(double d) const {return (long)(d + 66);}
   long f67(double d) const {return (long)(d + 67);}
   long f68(double d) const {return (long)(d + 68);}
   long f69(double d) const {return (long)(d + 69);}
   long f70(double d) const {return (long)(d + 70);}
   long f71(double d) const {return (long)(d + 71);}
   long f72(double d) const {return (long)(d + 72);}
   long f73(double d) const {return (long)(d + 73);}
   long f74(double d) const {return (long)(d + 74);}
   long f75(double d) const {return (long)(d + 75);}
   long f76(double d) const {return (long)(d + 76);}
   long f77(double d) const {return (long)(d + 77);}
   long f78(double d) const {return (long)(d + 78);}
   long f79(double d) const {return (long)(d + 79);}
   long f80(double d) const {return (long)(d + 80);}
   long f81(double d) const {return (long)(d + 81);}
   long f82(double d) const {return (long)(d + 82);}
   long f83(double d) const {return (long)(d + 83);}
   long f84(double d) const {return (long)(d + 84);}
   long f85(double d) const {return (long)(d + 85);}
   long f86(double d) const {return (long)(d + 86);}
   long f87(double d) const {return (long)(d + 87);}
   long f88(double d) const {return (long)(d + 88);}
   long f89(double d) const {return (long)(d + 89);}
   long f90(double d) const {return (long)(d + 90);}
   long f91(double d) const {return (long)(d + 91);}
   long f92(double d) const {return (long)(d + 92);}
   long f93(double d) const {return (long)(d + 93);}
   long f94(double d) const {return (long)(d + 94);}
   long f95(double d) const {return (long)(d + 95);}
   long f96(double d) const {return (long)(d + 96);}
   long f97(double d) const {return (long)(d + 97);}
   long f98(double d) const {return (long)(d + 98);}
   long f99(double d) const {return (long)(d + 99);}
   long f100(double d) const {return (long)(d + 100);}
   long f101(double d) const {return (long)(d + 101);}
   long f102(double d) const {return (long)(d + 102);}
   long f103(double d) const {return (long)(d + 103);}
   long f104(double d) const {return (long)(d + 104);}
   long f105(double d) const {return (long)(d + 105);}
   long f106(double d) const {return (long)(d + 106);}
   long f107(double d) const {return (long)(d + 107);}
   long f108(double d) const {return (long)(d + 108);}
   long f109(double d) const {return (long)(d + 109);}
   long f110(double d) const {return (long)(d + 110);}
   long f111(double d) const {return (long)(d + 111);}
   long f112(double d) const {return (long)(d + 112);}
   long f113(double d) const {return (long)(d + 113);}
   long f114(double d) const {return (long)(d + 114);}
   long f115(double d) const {return (long)(d + 115);}
   long f116(double d) const {return (long)(d + 116);}
   long f117(double d) const {return (long)(d + 117);}
   long f118(double d) const {return (long)(d + 118);}
   long f119(double d) const {return (long)(d + 119);}
   long f120(double d) const {return (long)(d + 120);}
   long f121(double d) const {return (long)(d + 121);}
   long f122(double d) const {return (long)(d + 122);}
   long f123(double d) const {return (long)(d + 123);}
   long f124(double d) const {return (long)(d + 124);}
   long f125(double d) const {return (long)(d + 125);}
   long f126(double d) const {return (long)(d + 126);}
   long f127(double d) const {return (long)(d + 127);}
   long f128(double d) const {return (long)(d + 128);}
   long f129(double d) const {return (long)(d + 129);}
   long f130(double d) const {return (long)(d + 130);}
   
private:
   Klass* fKlass;
};

unsigned long func(Long64_t& a, double b, const Klass& c) {
   if (--a > b) return func(a, b, c);
   return (unsigned long) c.get();
}

class InterpreterStress {
public:
   InterpreterStress(const char* binary): fNtimes(10), fBinary(binary) {
      fNames.push_back("FuncCall");
      fNames.push_back("STLDict");
      fNames.push_back("Reflection");
      fNames.push_back("NestedStatements");
   }

   bool run(Int_t ntimes = 10, const char* runTests = 0);

   bool stressFuncCall();

   void prepareSTLDict();
   bool stressSTLDict();

   bool stressReflection();

   bool stressNestedStatements();

   std::vector<std::string> fNames;

private:
   void runPreps() {
      prepareSTLDict();
   }

   Int_t fNtimes;
   TString fBinary;
};

/////////////////////////////////////////////////////////////////
// Test function call performance

bool InterpreterStress::stressFuncCall() {

   // This is fast.
   int ntimes = fNtimes * 100000;

   Klass c;
   unsigned long res[2];
   res[0] = res[1] = 0;

   int depth = 6; // That's all that Windows can handle...
   for (int i = 0; i < ntimes / depth; ++i) {
      // Call recursively:
      Long64_t a = depth;
      res[0] = func(a, 0., c);
   }

   // Call non-recursively:
   for (Long64_t a = ntimes; a > 0;) {
      res[1] = func(a, a - 1, c);
   }
   if (res[0] != (unsigned long)&c) return false;
   if (res[0] != res[1]) return false;
   return true;
}


/////////////////////////////////////////////////////////////////
// Test custom STL dictionary / calls
void InterpreterStress::prepareSTLDict() {
   // Remove AutoDict
   void* dir = gSystem->OpenDirectory(gSystem->pwd());
   const char* name = 0;
   while ((name = gSystem->GetDirEntry(dir))) {
      if (!strncmp(name, "AutoDict_", 9)) {
         gSystem->Unlink(name);
      }
   }
   gSystem->FreeDirectory(dir);
}
bool InterpreterStress::stressSTLDict() {
   using namespace std;

   bool allres = true;
   for (Int_t i = 1; i < fNtimes; ++i) {
      int res = 3;
      TInterpreter::EErrorCode interpError = TInterpreter::kNoError;
      TString cmd = TString::Format("#include <vector>\nclass MyClass;\ntypedef MyClass* Klass%d_t;\nstd::vector<Klass%d_t> v%d;\nvoid stressInterpreter_tmp%d() {\n   v%d.push_back((Klass%d_t)0x12);\n   *((int*)0x%lx) = 0;}", i, i, i, i, i, i, (unsigned long) &res);
      TString tmpfilename = TString::Format("stressInterpreter_tmp%d.C", i);
      {
         std::ofstream otmp(tmpfilename.Data());
         otmp << cmd << endl;
      }
      gInterpreter->ProcessLine(TString(".X ") + tmpfilename, &interpError);
      gSystem->Unlink(tmpfilename);
      allres &= (interpError == TInterpreter::kNoError);
      allres &= (res == 0);
   }
   return allres;
}

/////////////////////////////////////////////////////////////////
// Test reflection query, reflection-based function call
bool InterpreterStress::stressReflection() {

   // This is fast
   int ntimes = fNtimes * 800;

#if !defined(__CINT__) && !defined(__CLING__)
   TString macro(fBinary);
   macro += ".cxx";
   gInterpreter->LoadMacro(macro);
#endif
   int numfuncs = Klass::last_klf - Klass::first_klf + 1;
   bool success = true;
   for (Int_t i = 0; i < ntimes; ++i) {
      int funcnum = i % (Long64_t)(1.2 * numfuncs);
      TString fname = TString::Format("f%d", funcnum);
      ClassInfo_t* k = gInterpreter->ClassInfo_Factory("Klass");
      bool hasMethod = gInterpreter->ClassInfo_HasMethod(k, fname.Data());
      if (hasMethod != (funcnum >= Klass::first_klf && funcnum <= Klass::last_klf)) {
         success = false;
      }
      if (!hasMethod) {
         gInterpreter->ClassInfo_Delete(k);
         continue;
      }

      MethodInfo_t* mk = gInterpreter->CallFunc_Factory();
      Long_t offset = -1;
      gInterpreter->CallFunc_SetFuncProto(mk, k, fname, "double", &offset);
      if (!gInterpreter->CallFunc_IsValid(mk)) {
         success = false;
         gInterpreter->CallFunc_Delete(mk);
         gInterpreter->ClassInfo_Delete(k);
         continue;
      }
      if (offset != 0) {
         success = false;
         gInterpreter->CallFunc_Delete(mk);
         gInterpreter->ClassInfo_Delete(k);
         continue;
      }

      gInterpreter->CallFunc_SetArg(mk, -funcnum * 2 + 0.2);

      void* obj = gInterpreter->ClassInfo_New(k);
      if (!obj) {
         success = false;
         gInterpreter->CallFunc_Delete(mk);
         gInterpreter->ClassInfo_Delete(k);
         continue;
      }

      long ret = gInterpreter->CallFunc_ExecInt(mk, obj);
      if (ret != (long) (funcnum + (-funcnum * 2 + 0.2))) {
         success = false;
         gInterpreter->CallFunc_Delete(mk);
         gInterpreter->ClassInfo_Delete(k);
         continue;
      }

      gInterpreter->ClassInfo_Delete(k, obj);

      gInterpreter->CallFunc_Delete(mk);
      gInterpreter->ClassInfo_Delete(k);
   }

   return success;
}

/////////////////////////////////////////////////////////////////
// Test nested compound statements (if, switch, for,...)
bool InterpreterStress::stressNestedStatements() {
   bool success = true;
   int ntimes = fNtimes * 4;
   for (int i = 0; i < ntimes; ++i) {
      for (unsigned int pattern = 0; pattern < 0xff; ++pattern) {
         for (unsigned int bit = 0; bit < sizeof(Long64_t)*7; ++bit) {
            ULong64_t v = 1; // always > 0
            switch (pattern & 0xf) {
            case 1: v += 1;
            case 3: v += 3;
            case 5: v += 5;
            case 7: v += 7;
            case 9: v += 9;
            case 11: v += 11;
            case 13: v += 13;
            case 15: v += 15;
            default:
               v += (pattern & 0xf);
            }
            v = v << bit;

            if (bit < 32) {
               if (v > (1ll << 48)) success = false;
            } else {
               if (pattern) {
                  if (!v || v < 1) success = false;
                  else {
                     if (bit > 0 && v == pattern && pattern > 0) {
                        if (success)
                           success = false;
                     }
                  }
               } else {
                  if (success) success = true;
               }
            }
            while (v) v = v >> 1;
            if (v) success = false;
         }
      }
   }
   return success;
}

/////////////////////////////////////////////////////////////////
// Driver

bool InterpreterStress::run(Int_t ntimes /*= 10*/, const char* runTests /*= 0*/) {
   using namespace std;
   static const char* benchmark = "stressInterpreter";

   fNtimes = ntimes;

   runPreps();

   gBenchmark->Start(benchmark);
   cout << "****************************************************************************" <<endl;
   cout << "*  Starting  stress INTERPRETER                                            *" <<endl;
   cout << "****************************************************************************" <<endl;
   bool success = true;
   for (unsigned int itest = 0; itest < fNames.size(); ++itest) {
      if (runTests && runTests[0]) {
         // only run test if it was selected
         if (!strstr(fNames[itest].c_str(), runTests)) continue;
      }
      bool res = false;
      switch (itest) {
      case 0: res = stressFuncCall(); break;
      case 1: res = stressSTLDict(); break;
      case 2: res = stressReflection(); break;
      case 3: res = stressNestedStatements(); break;
      }
      success &= res;
      printf("%s %s%s\n", fNames[itest].c_str(), TString('.', 77 - fNames[itest].length() - 8).Data(), (res ? "... OK" : " FAILED"));
   }

   // Summary:
   gBenchmark->Stop(benchmark);
   Double_t reftime100 = 600; //pcbrun compiled
   Double_t ct = gBenchmark->GetCpuTime(benchmark);
   const Double_t rootmarks = 800*reftime100*ntimes/(100*ct);
   printf("****************************************************************************\n");

   gBenchmark->Print(benchmark);
   printf("****************************************************************************\n");
   printf("*  ROOTMARKS =%6.1f   *  Root%-8s  %d/%d\n",rootmarks,gROOT->GetVersion(),
         gROOT->GetVersionDate(),gROOT->GetVersionTime());
   printf("****************************************************************************\n");
   return success;
}

bool stressInterpreter(Int_t ntimes = 10, const char* runTests = 0, const char* binary = "") {
   // Since this routine can be called (almost) directly from the command line and is used
   // in automated test, it must return 0 in case of success
   InterpreterStress stress(binary);
   return !stress.run(ntimes, runTests);
}

#if !defined(__CINT__) && !defined(__CLING__)
// If compiled: interpret! (by default)

int main(int argc, char **argv)
{
   Int_t ntimes = 2;
   bool runInterpreted = true;
   TString runTests;

   for (int iarg = 1; iarg < argc; ++iarg) {
      const char* arg = argv[iarg];
      if (arg[0] == '-') {
         if (!strcmp(arg, "--help")) {
            printf("Interpreter speed test\n");
            printf("Run as: %s [--help] [-c] [--test=...] [num]\n", gSystem->BaseName(argv[0]));
            printf("  --help: print this help\n");
            printf("  -c: run compiled\n");
            TString alltests;
            InterpreterStress tmp("");
            for (unsigned int i = 0; i < tmp.fNames.size(); ++i) alltests += TString(" ") + tmp.fNames[i];
            printf("  --test=...: run only given test, one of%s\n", alltests.Data());
            printf("  num: run for num iterations (default: %d)\n", ntimes);
            return 0;
         }
         if (!strcmp(arg, "-c")) {
            runInterpreted = false;
            continue;
         }
         if (!strncmp(arg, "--test=", 7)) {
            runTests = arg + 7;
            continue;
         }
      } else {
         ntimes = atoi(argv[1]);
      }
   }

   gROOT->SetBatch();
   TApplication theApp("App", &argc, argv);

   TString exe(argv[0]);
   if (exe.EndsWith(".exe")) exe.Remove(exe.Length() - 4, 4);

   gBenchmark = new TBenchmark();

   if (runInterpreted) {
      TString cmd = TString::Format(".L %s.cxx", exe.Data());
      gInterpreter->ProcessLine(cmd);
      exe = gSystem->BaseName(exe);
      cmd = TString::Format("%s(%d, \"%s\", \"%s\")", exe.Data(), ntimes, runTests.Data(), exe.Data());
      if (0 != gInterpreter->ProcessLine(cmd)) return 1;
   } else {
      if (0 != stressInterpreter(ntimes, runTests, exe)) return 1;
   }
   return 0;
}
#endif