1/* Hash timing test harness
2 *
3 * Usage: mkhash opts count
4 *
5 * 	opts is a combination of the following flags (default "Dhs"):
6 * 		d	store data view flat
7 * 		D	store data view blocked
8 * 		m	store map view flat
9 * 		M	store map view blocked
10 * 		h	use hashing
11 * 		H	use hashing, after filling the view
12 * 		o	use ordering
13 * 		2	2-key hashing/ordering, instead of 1-key
14 * 		s	time small (2-row add) commits, i.s.o. 1000 rows
15 * 		f	do frequent commits, every 10 i.s.o. 1000 rows
16 *
17 * 	count is the total number of rows added, default is 250,000
18 *      (it should be a multiple of 10,000 for proper reporting)
19 *
20 *  % g++ -Dq4_INLINE mkhash.cpp -lmk4
21 *  % for i in - d D dh Dh dmh Dmh do Do; do rm -f test.dat; a.out $i; done
22 *  [...]
23 */
24
25#include <mk4.h>
26#include <stdio.h>
27#include <stdlib.h>
28#include <string.h>
29
30#ifdef WIN32
31  #define WIN32_LEAN_AND_MEAN
32  #include <windows.h>
33
34  long ticks ()
35  {
36    LARGE_INTEGER t;
37
38    static double f = 0.0;
39    if (f == 0.0) {
40      QueryPerformanceFrequency(&t);
41      f = (double) t.QuadPart / 1000000.0;
42    }
43
44    QueryPerformanceCounter(&t);
45    return (long) (f * t.QuadPart);
46  }
47#else
48  #include <sys/time.h>
49  #include <sys/types.h>
50  #include <sys/stat.h>
51
52  long ticks()
53  {
54    struct timeval tv;
55    struct timezone tz;
56    gettimeofday(&tv, &tz);
57    return tv.tv_sec * 1000000 + tv.tv_usec;
58  }
59#endif
60
61int main(int argc, char **argv)
62{
63  char buf [25];
64  c4_Row row;
65  long t;
66  int nkeys = 1;
67
68  //setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
69
70  c4_Storage storage ("test.dat", true);
71
72  c4_StringProp pKey ("key"), pKey2 ("key2");
73  c4_View data = pKey;
74
75  c4_IntProp pH ("_H"), pR ("_R");
76  c4_View map = (pH, pR);
77  const char *s = argc > 1 ? argv[1] : "Dhs";
78
79  if (strchr(s, '2')) {
80    // must create properties in same order as in the hash view (ouch!)
81    pKey (row) = "";
82    pKey2 (row) = "abcdefghijklmnopqrstuvwxyz";
83    nkeys = 2;
84    if (strchr(s, 'd'))
85      data = storage.GetAs("data[key:S,key2:S]");
86    if (strchr(s, 'D')) {
87      data = storage.GetAs("data[_B[key:S,key2:S]]");
88      data = data.Blocked();
89    }
90  } else {
91    if (strchr(s, 'd'))
92      data = storage.GetAs("data[key:S]");
93    if (strchr(s, 'D')) {
94      data = storage.GetAs("data[_B[key:S]]");
95      data = data.Blocked();
96    }
97  }
98
99  if (strchr(s, 'm'))
100    map = storage.GetAs("map[_H:I,_R:I]");
101  if (strchr(s, 'M')) {
102    map = storage.GetAs("map[_B[_H:I,_R:I]]");
103    map = map.Blocked();
104  }
105  if (strchr(s, 'h'))
106    data = data.Hash(map, nkeys);
107  if (strchr(s, 'o'))
108    data = data.Ordered(nkeys);
109  int cfreq = strchr(s, 'f') ? 10 : 1000;
110
111  int limit = 250000;
112  if (argc > 2)
113    limit = atoi(argv[2]);
114
115  puts(s);
116  puts("      ROW       ADD         FIND       COMMIT         SIZE");
117
118  for (int i = 1; i <= limit; ++i) {
119    sprintf(buf, "%10d%10d", 100000000 + i, 200000000 + i);
120
121    pKey (row) = buf;
122
123    t = ticks();
124    data.Add(row);
125    long at = ticks() - t;
126
127    if ((i+2) % cfreq == 0 && strchr(s, 's'))
128      storage.Commit();
129
130    if (i % cfreq == 0) {
131      t = ticks();
132      storage.Commit();
133      long ct = ticks() - t;
134
135      if (i % (limit/10) == 0) {
136	t = ticks();
137	int n = data.Find(row);
138	long ft = ticks() - t;
139
140	if (n < 0) { puts(buf); return 1; }
141
142	printf("%9d %9d uS %9d uS %9d uS %9d bytes \n",
143	    	i, at, ft, ct, storage.Strategy().FileSize());
144      }
145    }
146  }
147
148  if (strchr(s, 'H')) {
149    t = ticks();
150    data = data.Hash(map, nkeys);
151    long ht = ticks() - t;
152
153    t = ticks();
154    storage.Commit();
155    long ct = ticks() - t;
156
157    printf("construct hash: %d uS, then commit: %d uS\n", ht, ct);
158    fflush(stdout);
159  }
160
161  return 0;
162}
163