source: benchmark/io/http/filecache.cfa @ 5936244

arm-ehjacob/cs343-translationnew-ast-unique-expr
Last change on this file since 5936244 was 5936244, checked in by Thierry Delisle <tdelisle@…>, 12 months ago

Fixed errors in httop benchmark

  • Property mode set to 100644
File size: 5.2 KB
Line 
1#include "filecache.hfa"
2
3#include <assert.h>
4#include <string.h>
5
6#include <stdlib.hfa>
7
8#include <errno.h>
9#include <unistd.h>
10extern "C" {
11        #include <fcntl.h>
12        #include <ftw.h>
13}
14
15#include "options.hfa"
16
17static inline uint32_t murmur_32_scramble(uint32_t k) {
18    k *= 0xcc9e2d51;
19    k = (k << 15) | (k >> 17);
20    k *= 0x1b873593;
21    return k;
22}
23
24uint32_t murmur3_32(const uint8_t* key, size_t len, uint32_t seed)
25{
26        uint32_t h = seed;
27        uint32_t k;
28        /* Read in groups of 4. */
29        for (size_t i = len >> 2; i; i--) {
30                // Here is a source of differing results across endiannesses.
31                // A swap here has no effects on hash properties though.
32                memcpy(&k, key, sizeof(uint32_t));
33                key += sizeof(uint32_t);
34                h ^= murmur_32_scramble(k);
35                h = (h << 13) | (h >> 19);
36                h = h * 5 + 0xe6546b64;
37        }
38        /* Read the rest. */
39        k = 0;
40        for (size_t i = len & 3; i; i--) {
41                k <<= 8;
42                k |= key[i - 1];
43        }
44        // A swap is *not* necessary here because the preceding loop already
45        // places the low bytes in the low places according to whatever endianness
46        // we use. Swaps only apply when the memory is copied in a chunk.
47        h ^= murmur_32_scramble(k);
48        /* Finalize. */
49        h ^= len;
50        h ^= h >> 16;
51        h *= 0x85ebca6b;
52        h ^= h >> 13;
53        h *= 0xc2b2ae35;
54        h ^= h >> 16;
55        return h;
56}
57
58static inline [unsigned size, char unit] human_size( size_t size ) {
59        int idx = 0;
60        static char units [] = { ' ', 'K', 'M', 'G', 'T' };
61        while( size >= 1024 ) {
62                idx++;
63                size /= 1024;
64                if(idx >= 5) {
65                        abort("File too large to print\n");
66                }
67        }
68
69        return [size, units[idx]];
70}
71
72struct {
73        cache_line * entries;
74        size_t size;
75        int * rawfds;
76        int nfds;
77} file_cache;
78
79void ?{}( cache_line & this ) with( this ) {
80        file = 0p;
81        size = 0;
82        fd   = 0;
83}
84
85[int fd, size_t size] get_file( * const char file, size_t len ) {
86        uint32_t idx = murmur3_32( (const uint8_t *)file, len, options.file_cache.hash_seed ) % file_cache.size;
87
88        for(int i = 0;; i++) {
89                assert( i < file_cache.size );
90                cache_line & entry = file_cache.entries[idx];
91                if( !entry.file ) return [-1, 0];
92                #if !defined(REJECT_CONFLICTS)
93                        if( strncmp(entry.file, file, len) != 0 ) {
94                                idx = (idx + 1) % file_cache.size;
95                                continue;
96                        }
97                #endif
98                return [entry.fd, entry.size];
99        }
100}
101
102int put_file( cache_line & entry, int fd ) {
103        uint32_t idx = murmur3_32( (const uint8_t *)entry.file, strlen(entry.file), options.file_cache.hash_seed ) % file_cache.size;
104
105        int i = 0;
106        for(;file_cache.entries[idx].file; i++ ) {
107                assert( i < file_cache.size );
108                idx = (idx + 1) % file_cache.size;
109        }
110
111        file_cache.entries[idx] = entry;
112        file_cache.entries[idx].fd = fd;
113        return i > 0 ? 1 : 0;
114}
115
116// int ftw(const char *dirpath, int (*fn) (const char *fpath, const struct stat *sb, int typeflag), int nopenfd)
117void fill_cache( const char * path ) {
118        int ret;
119        ret = chdir(path);
120        if(ret < 0) {
121                abort( "chdir error: (%d) %s\n", (int)errno, strerror(errno) );
122        }
123
124        size_t fcount = 0;
125        size_t fsize = 16;
126        cache_line * raw = alloc(fsize);
127        // Step 1 get a dense array of all files
128        int walk(const char *fpath, const struct stat *sb, int typeflag) {
129                if(typeflag != FTW_F) return 0;
130
131                int idx = fcount;
132                fcount++;
133                if(fcount > fsize) {
134                        fsize *= 2;
135                        raw = alloc(fsize, raw`realloc);
136                }
137
138                raw[idx].file = strdup(fpath+2);
139                raw[idx].size = sb->st_size;
140                if( !options.file_cache.list ) {
141                        raw[idx].fd = open( fpath, options.file_cache.open_flags );
142                        if(raw[idx].fd < 0) {
143                                abort( "open file error: (%d) %s\n", (int)errno, strerror(errno) );
144                        }
145                }
146                return 0;
147        }
148
149        ret = ftw(".", walk, 10);
150        if(ret < 0) {
151                abort( "ftw error: (%d) %s\n", (int)errno, strerror(errno) );
152        }
153
154        if(fcount == 0) {
155                abort("No file found in path %s\n", path);
156        }
157
158        // Step 2 create the cache
159        file_cache.size = options.file_cache.size > 0 ? options.file_cache.size : fsize;
160        if( file_cache.size < fcount ) {
161                abort("File Cache too small\n");
162        }
163
164        file_cache.entries = anew(file_cache.size);
165
166        if(options.file_cache.fixed_fds) {
167                file_cache.nfds   = fcount;
168                file_cache.rawfds = alloc(fcount);
169        }
170
171        // Step 3 fill the cache
172        int conflicts = 0;
173        for(i; fcount) {
174                int fd;
175                if(options.file_cache.fixed_fds) {
176                        file_cache.rawfds[i] = raw[i].fd;
177                        fd = i;
178                }
179                else {
180                        fd = raw[i].fd;
181                }
182                conflicts += put_file( raw[i], fd );
183        }
184        printf("Filled cache from path \"%s\" with %zu files\n", path, fcount);
185        if( conflicts > 0 ) {
186                printf("Found %d conflicts (seed: %u)\n", conflicts, options.file_cache.hash_seed);
187                #if defined(REJECT_CONFLICTS)
188                        abort("Conflicts found in the cache");
189                #endif
190        }
191
192        if(options.file_cache.list) {
193                printf("Listing files and exiting\n");
194                for(i; fcount) {
195                        int s; char u;
196                        [s, u] = human_size(raw[i].size);
197                        printf("%4d%c - %s\n", s, u, raw[i].file);
198                        free(raw[i].file);
199                }
200                free(raw);
201                adelete( file_cache.entries );
202                exit(0);
203        }
204
205        // Step 4 clean up
206        free( raw );
207}
208
209[int *, int] filefds(int extra) {
210        if(!file_cache.entries) {
211                abort("File cache not filled!\n");
212        }
213
214        size_t s = file_cache.nfds + extra;
215        int * data = alloc(s, file_cache.rawfds`realloc);
216        return [data, file_cache.nfds];
217}
218
219
220void close_cache() {
221        for(idx; file_cache.size) {
222                cache_line & entry = file_cache.entries[idx];
223                if( !entry.file ) continue;
224
225                int ret = close( entry.fd );
226                if(ret < 0) {
227                        abort( "close file error: (%d) %s\n", (int)errno, strerror(errno) );
228                }
229        }
230
231        delete( file_cache.entries );
232}
Note: See TracBrowser for help on using the repository browser.