diff --git a/tp/tp1/README.md b/tp/tp1/README.md new file mode 100644 index 0000000..3b830f9 --- /dev/null +++ b/tp/tp1/README.md @@ -0,0 +1,258 @@ +# TP1 : Mémoire + +> Dans le répertoire [scripts](./src/scripts), vous avez 2 scripts qui permettent de formater sur la sortie standard les +> interfaces `/proc/pid/maps` et `/proc/pid/smaps` d'un processus quelconque. + +#### Ex1 + +Compilez avec `g++` le programme [alignement.c](./src/alignement.c), et +exécutez. Vérifiez qie la taille et l'alignement de chaque structure est bien +conforme aux règles vues en cours. + +#### Ex2 + +Soit le [programme](./src/adresses_virtuelles.c) suivant qui affiche les +adresses virtuelles de certaines variables lors de l'exécution du processus +correspondant : + +```c +/* adresses virtuelles d'un processus */ + +#include +#include +#include +#include + +int t[1000] = {[0 ... 999] = 2}; + +int main(int argc, char * argv[]) +{ + int i=3; + static int j = 3; + char * m = (char*)malloc(1); + printf("je suis le pid %d\n\n",getpid()); + /* ------- Affichage des adresses --------*/ + printf("main\t=\t%p\n",main); + printf("&argc\t=\t%p\n",&argc); + printf("&i\t=\t%p\n",&i); + printf("&j\t=\t%p\n",&j); + printf("t\t=\t%p\n",t); + printf("m\t=\t%p\n",m); + + getchar(); +} +``` + +En utilisant le (pseudo) fichier `/proc/pid/maps`, vérifiez à quel segment de +pages ces adresses appartiennent. Vous pouvez utiliser le script python +[vmap.py](./src/scripts/vmap.py). + +#### Ex3 + +L'interface (pseudo-fichier) `proc/pid/smaps` montre la consommation mémoire +d'un processus. On peut le formater avec la commande `pmap -X` ou avec le script +python [parse_smaps.py](./src/scripts/parse_smaps.py). Le but de l'exercice est +de voir ce qui se passe au niveau de la mémoire d'un processus suivant les +différents mode d'allocation. Le programme `null.c` permet d'avoir un point de +comparaison. Vérifiez la consommation mémoire dans les cas suivants : + +1. Allocation statique [buf.c](./src/ex3/buf.c). +2. Allocation sur la pile [stack.c](./src/ex3/stack.c), +3. Allocation sur le tas [heap.c](./src/ex3/heap.c), +4. Allocation (grande quantité) sur le tas [huge.c](./src/ex3/huge.c). +5. Allocation par mapping [mmap.c](./src/ex3/mmap.c). + +#### Ex4 + +Soit le [programme](./src/bss_data.c) suivant : + +```c +/* segment bss et data */ +#define N 10000 +int t[N]; /* version 1 */ +//int t[N]={1}; /* version 2 */ + +int main() +{ + return 0; +} +``` + +1. Compilez le programme. Avec la commande `size`, regardez les différents segments du programme. Où se trouve le tableau `t` ? Augmentez la valeur de N. La taille de l'exécutable a-t-elle changé ? pourquoi ? +2. Recommencez avec la version 2. Expliquez. + +#### Ex5 + +Soit le [programme](./src/ij_ji.c) suivant : + +```c +/* accès mémoire */ +#include +#include +#include +#define N 8192 + +int t[N][N]; + +static inline double tstamp(void) +{ + struct timespec tv; + clock_gettime(CLOCK_REALTIME, &tv); + return tv.tv_sec + tv.tv_nsec * 1.0e-9; +} + +int main() +{ + int i,j; + double t1,t2; + t1=tstamp(); + /* version 1 */ for(i=0;i+---------------------------+ + |###########################| \ + |###########################| | + |###########################| | already allocated + |###########################| | + |###########################| | + |###########################| / + pos +-------------->----------------------------+ + | | \ + | | | + | | | + | | | + | | | + | | | free space + | | | + | | | + | | | + | | | + | | | + | | / + +---------------------------+ +``` + +C'est la fonction +```c +void * my_alloc(size_t sz) +``` + +qui s'occupe de renvoyer l'adresse d'un bloc libre. On ne se préoccupe pas de désallocation, ni d'alignement. Une allocation consiste simplement à incrémenter (si c'est possible) +la valeur de `pos`, et à retourner l'adresse du bloc alloué. + +Implanter cette fonction, et tester. + + +#### Ex8 +Ecrire une fonction +```c +void hexdump(void * ptr,size_t size); +``` + +qui affiche sur la sortie standard le contenu de la mémoire `[ptr,ptr+size[` au format : + +``` +XXXXXXXX BB BB BB BB BB BB BB BB BB BB BB BB BB BB BB BB |CCCCCCCCCCCCCCCC| +``` + +(comme la commande shell) + + - `XXXXXXXXX` représente l'adresse du premier octet de la ligne + - `BB` la valeur hexadécimale de chaque octet + - `|CCCCCCCCCCCCCCCC|` la correspondance ascii de chaque octet (`.` si non affichable) + +Testez avec les objets suivants et expliquez : +```c +/* alignement et objets */ +struct exemple1 { + int x; + int y; + int z; + int w; +}; + +struct exemple2 { + char x; + char y; + char z; + char w; +}; + +struct exemple3 { + int x; + int y; + char z; + char w; +}; + +struct exemple4 { + int x; + char y; + int z; + char w; +}; + +union exemple5 { + int x; + char y; + int z; + char w; +}; + +int main() +{ + int a[4] = {1,2,3,4}; + char c[4] = {'a','b','c','d'}; + struct exemple1 ex1 = {1,2,3,4}; + struct exemple2 ex2 = {'a','b','c','d'}; + struct exemple3 ex3 = {1,2,'c','d'}; + struct exemple4 ex4 = {1,'c',2,'d'}; + union exemple5 ex5; + int x = 61; + char y = 62; + int z = 63; + char w = 64; + ex5.x=62;ex5.y=63;ex5.z=64;ex5.w=65; + + // appelez hexdump pour chaque variable + + + return 0; +} +``` + +Est-ce conforme à ce que l'on a vu en cours concernant l'alignement en mémoire ? + + diff --git a/tp/tp1/src/adresses_virtuelles.c b/tp/tp1/src/adresses_virtuelles.c new file mode 100644 index 0000000..fe6c824 --- /dev/null +++ b/tp/tp1/src/adresses_virtuelles.c @@ -0,0 +1,29 @@ +/* adresses virtuelles d'un processus */ + +#include +#include +#include +#include + +int t[1000] = {[0 ... 999] = 2}; + +int main(int argc, char * argv[]) +{ + int i=3; + static int j = 3; + char * m = (char*)malloc(1); + + printf("mon pid est %d\n\n",getpid()); + + /* ------- Affichage des adresses --------*/ + + printf("main\t=\t%p\n",main); + printf("&argc\t=\t%p\n",&argc); + printf("&i\t=\t%p\n",&i); + printf("&j\t=\t%p\n",&j); + printf("t\t=\t%p\n",t); + printf("m\t=\t%p\n",m); + + getchar(); +} + diff --git a/tp/tp1/src/alignement.c b/tp/tp1/src/alignement.c new file mode 100644 index 0000000..af17aeb --- /dev/null +++ b/tp/tp1/src/alignement.c @@ -0,0 +1,55 @@ +/* alignement et objets */ + +struct exemple1 { + int x; + int y; + int z; + int w; +}; + +struct exemple2 { + char x; + char y; + char z; + char w; +}; + +struct exemple3 { + int x; + int y; + char z; + char w; +}; + +struct exemple4 { + int x; + char y; + int z; + char w; +}; + +union exemple5 { + int x; + char y; + int z; + char w; +}; + +int main() +{ + int a[4] = {1,2,3,4}; + char c[4] = {'a','b','c','d'}; + struct exemple1 ex1 = {1,2,3,4}; + struct exemple2 ex2 = {'a','b','c','d'}; + struct exemple3 ex3 = {1,2,'c','d'}; + struct exemple4 ex4 = {1,'c',2,'d'}; + union exemple5 ex5; + int x = 61; + char y = 62; + int z = 63; + char w = 64; + ex5.x=62;ex5.y=63;ex5.z=64;ex5.w=65; + + // appelez hexdump pour chaque variable +} + diff --git a/tp/tp1/src/bss_data.c b/tp/tp1/src/bss_data.c new file mode 100644 index 0000000..b34c3db --- /dev/null +++ b/tp/tp1/src/bss_data.c @@ -0,0 +1,10 @@ +/* segment bss et data */ +#define N 1000 +int t[N]; /* version 1 */ +//int t[N]={1}; /* version 2 */ + +int main() +{ + return 0; +} + diff --git a/tp/tp1/src/ex3/Makefile b/tp/tp1/src/ex3/Makefile new file mode 100644 index 0000000..f6ddfde --- /dev/null +++ b/tp/tp1/src/ex3/Makefile @@ -0,0 +1,17 @@ +CFLAGS := -Wall -g -O0 +SRC=buf.c heap.c huge.c mmap.c null.c stack.c + +DEPENDHELPERS=helpers.o + +BINARIES=$(SRC:%.c=%) + +%.o : %c + gcc -c $+ + +$(BINARIES): % : %.o $(DEPENDHELPERS) + gcc -o $@ $+ + +all : $(BINARIES) + +clean: + rm -f *.o $(BINARIES) diff --git a/tp/tp1/src/ex3/buf.c b/tp/tp1/src/ex3/buf.c new file mode 100644 index 0000000..3530209 --- /dev/null +++ b/tp/tp1/src/ex3/buf.c @@ -0,0 +1,9 @@ +#include "helpers.h" + +static char buf[16 MB] = {0}; + +int main(int argc, char **argv) +{ + randomize(buf, 16 MB); + return interlude(); +} diff --git a/tp/tp1/src/ex3/data/256k b/tp/tp1/src/ex3/data/256k new file mode 100644 index 0000000..f3e3746 Binary files /dev/null and b/tp/tp1/src/ex3/data/256k differ diff --git a/tp/tp1/src/ex3/heap.c b/tp/tp1/src/ex3/heap.c new file mode 100644 index 0000000..196ecb9 --- /dev/null +++ b/tp/tp1/src/ex3/heap.c @@ -0,0 +1,8 @@ +#include "helpers.h" + +int main(int argc, char **argv) +{ + dirty(16 MB); + clean(32 MB); + return interlude(); +} diff --git a/tp/tp1/src/ex3/helpers.c b/tp/tp1/src/ex3/helpers.c new file mode 100644 index 0000000..1a2799f --- /dev/null +++ b/tp/tp1/src/ex3/helpers.c @@ -0,0 +1,36 @@ +#include +#include +#include +#include +#include "helpers.h" + +#include + +void randomize(char *buf, size_t n) +{ + assert(buf); + memset(buf, rand() & 0xff, n); +} + +void clean(size_t b) +{ + for (; b > 0; b -= 1 KB) + calloc(1 KB, sizeof(char)); +} + +void dirty(size_t b) +{ + for (; b > 0; b -= 1 KB) + randomize(calloc(1 KB, sizeof(char)), 1 KB); +} + +int interlude(void) +{ + pid_t pid = getpid(); + printf("pid %i\n", (int)pid); + printf("------------------------------------------\n" + "go check /proc/%i/smaps; I'll wait...\n" + "press when you're done\n", pid); + fgetc(stdin); + return 0; +} diff --git a/tp/tp1/src/ex3/helpers.h b/tp/tp1/src/ex3/helpers.h new file mode 100644 index 0000000..d8a774a --- /dev/null +++ b/tp/tp1/src/ex3/helpers.h @@ -0,0 +1,13 @@ +#ifndef _HELPERS_H +#define _HELPERS_H +#include + +#define KB * 1024 +#define MB * 1024 * 1024 + +void randomize(char *buf, size_t n); +void clean(size_t n); +void dirty(size_t n); +int interlude(void); + +#endif diff --git a/tp/tp1/src/ex3/huge.c b/tp/tp1/src/ex3/huge.c new file mode 100644 index 0000000..046aea0 --- /dev/null +++ b/tp/tp1/src/ex3/huge.c @@ -0,0 +1,12 @@ +#include "helpers.h" + +int main(int argc, char **argv) +{ + char *under = malloc(96 KB); + randomize(under, 96 KB); + + char *over = malloc(256 KB); + randomize(over, 256 KB); + + return interlude(); +} diff --git a/tp/tp1/src/ex3/mmap.c b/tp/tp1/src/ex3/mmap.c new file mode 100644 index 0000000..ac62144 --- /dev/null +++ b/tp/tp1/src/ex3/mmap.c @@ -0,0 +1,38 @@ +#include "helpers.h" +#include +#include +#include + + +int main(int argc, char **argv) +{ + /* inert map (never modified) */ + char *inert = mmap(NULL, 16 KB, + PROT_READ|PROT_WRITE, + MAP_ANONYMOUS|MAP_PRIVATE, + -1, 0); + /* anonymous, private mmap */ + char *anon_priv = mmap(NULL, 32 KB, + PROT_READ|PROT_WRITE, + MAP_ANONYMOUS|MAP_PRIVATE, + -1, 0); + randomize(anon_priv, 32 KB); + + /* anonymous, shared map */ + char *anon_shared = mmap(NULL, 64 KB, + PROT_READ|PROT_WRITE, + MAP_ANONYMOUS|MAP_SHARED, + -1, 0); + randomize(anon_shared, 64 KB); + + /* private, file-backed map */ + int fd = open("data/256k", O_RDWR); + assert(fd >= 0); + char *file = mmap(NULL, 256 KB, + PROT_READ|PROT_WRITE, + MAP_PRIVATE, + fd, 0); + randomize(file, 128 KB); + + return interlude(); +} diff --git a/tp/tp1/src/ex3/null.c b/tp/tp1/src/ex3/null.c new file mode 100644 index 0000000..fbd46f7 --- /dev/null +++ b/tp/tp1/src/ex3/null.c @@ -0,0 +1,6 @@ +#include "helpers.h" + +int main(int argc, char **argv) +{ + return interlude(); +} diff --git a/tp/tp1/src/ex3/stack.c b/tp/tp1/src/ex3/stack.c new file mode 100644 index 0000000..700eef1 --- /dev/null +++ b/tp/tp1/src/ex3/stack.c @@ -0,0 +1,8 @@ +#include "helpers.h" + +int main (int argc, char **argv) +{ + char buf[28 KB] = {0}; + randomize(buf, 28 KB); + return interlude(); +} diff --git a/tp/tp1/src/ex7/Makefile b/tp/tp1/src/ex7/Makefile new file mode 100644 index 0000000..ae55ac6 --- /dev/null +++ b/tp/tp1/src/ex7/Makefile @@ -0,0 +1,11 @@ +alloc.o : alloc.c alloc.h + gcc -c alloc.c + +matrix.o : matrix.c + gcc -c matrix.c + +matrix : matrix.o alloc.o + gcc -o matrix matrix.o alloc.o + + +all : matrix diff --git a/tp/tp1/src/ex7/alloc.c b/tp/tp1/src/ex7/alloc.c new file mode 100644 index 0000000..5c31e47 --- /dev/null +++ b/tp/tp1/src/ex7/alloc.c @@ -0,0 +1,29 @@ +#include "alloc.h" +#include +#include +#include + +struct my_memory_buffer { + char* buffer; + size_t pos ; + size_t size ; +}; + +static struct my_memory_buffer my_buf; + + +__attribute__((constructor)) +static void my_module_initialize(void) +{ + // TODO + // Init my_buf (8Mo) + // with mmap +} + + +void * my_alloc(size_t sz) +{ + // TODO + return NULL; +} + diff --git a/tp/tp1/src/ex7/alloc.h b/tp/tp1/src/ex7/alloc.h new file mode 100644 index 0000000..17921b0 --- /dev/null +++ b/tp/tp1/src/ex7/alloc.h @@ -0,0 +1,8 @@ +#ifndef _ALLOC_H +#define _ALLOC_H + +#include + +void * my_alloc(size_t sz); + +#endif diff --git a/tp/tp1/src/ex7/matrix.c b/tp/tp1/src/ex7/matrix.c new file mode 100644 index 0000000..8ae1787 --- /dev/null +++ b/tp/tp1/src/ex7/matrix.c @@ -0,0 +1,76 @@ +#include +#include +#include +#include "alloc.h" +#include + +#define N 100 + +static inline double tstamp(void) { + struct timespec tv; + clock_gettime(CLOCK_REALTIME, &tv); + return tv.tv_sec + tv.tv_nsec * 1.0e-9; +} + +void init_matrix(int **a,int n) +{ + int i,j; + for(i=0;i +#include +#include +#define N 8192 + +int t[N][N]; + +static inline double tstamp(void) +{ + struct timespec tv; + clock_gettime(CLOCK_REALTIME, &tv); + return tv.tv_sec + tv.tv_nsec * 1.0e-9; +} + +int main() +{ + int i,j; + double t1,t2; + t1=tstamp(); + + /* version 1 */ + + for(i=0;i +# + +import sys +import os +import getopt +from collections import defaultdict, OrderedDict +from subprocess import check_output + +def usage(): + print(""" +usage: parse_smaps.py [-p process_name] [-t memory_type] [-h] [smaps_filename] + +example: parse_smaps.py /proc/12424/smaps + parse_smaps.py -p smbd + parse_smaps.py -p smbd -t Pss +""") + + +def print_header(mem_idx): + print('=' * 70) + for title in zip(*map(lambda x: x.split('_'), mem_idx.keys()), + ('', '= Total : library')): + print('{:>8} + {:>8} + {:>8} + {:>8} {}'.format(*title,)) + print('=' * 70) + + +def main(): + try: + opts, args = getopt.getopt(sys.argv[1:], 'p:t:ah', + ['process-name=', 'memory-type=', + 'all', 'help']) + except getopt.GetoptError as err: + print(err) + sys.exit(2) + + ps_name = '' + mem_type = '' + mem_idx = OrderedDict([ + ('Private_Clean', 0), + ('Private_Dirty', 1), + ('Shared_Clean', 2), + ('Shared_Dirty', 3) + ]) + for o, a in opts: + if o in ('-p', '--process-name'): + ps_name = a + elif o in ('-t', '--memory-type'): + mem_type = a + mem_idx = {a: 0} + else: + usage() + sys.exit(2) + + if (len(args) == 0 and ps_name == '') or len(args) > 1: + usage() + sys.exit(2) + + smaps_file = '' + if ps_name == '': + smaps_file = os.path.abspath(args[0]) + else: + try: + pids = check_output(['pidof', ps_name]).decode().strip().split() + if len(pids) > 1: + print('There are multiple pids:') + for i, p in enumerate(pids): + cmdline_file = '/proc/' + p + '/cmdline' + with open(cmdline_file, 'r') as cmdline: + line = next(cmdline) + print('[{}] {:>8}: {}'.format(i, p, line)) + num = input('Choose which one process you want (default=0): ') + num = int(num) if num != '' else 0 + pid = pids[num] + else: + pid = pids[0] + except Exception as err: + print(err) + sys.exit(1) + + smaps_file = '/proc/' + pid + '/smaps' + + mapinfo = defaultdict(lambda: [0] * len(mem_idx)) + total = [0] * len(mem_idx) + + with open(smaps_file, 'r') as smap: + for line in smap: + line_arr = line.split() + if '-' in line_arr[0]: + if len(line_arr) < 6: + filename = '[anonymous]' + else: + filename = os.path.basename(line_arr[-1]) + else: + line_arr[0] = line_arr[0].strip(':') + + if line_arr[0] in mem_idx: + mapinfo[filename][mem_idx[line_arr[0]]] += int(line_arr[1]) + total[mem_idx[line_arr[0]]] += int(line_arr[1]) + + if mem_type == '': + print_header(mem_idx) + + for filename, mem in sorted(mapinfo.items(), key=lambda x: -sum(x[1])): + print('{:>5} kB + {:>5} kB + {:>5} kB + {:>5} kB' + ' = {:>5} kB : {:<}'.format(*mem, sum(mem), filename)) + + print('=' * 70) + print('{:>5} kB + {:>5} kB + {:>5} kB + {:>5} kB' + ' = {:>5} kB : Total'.format(*total, sum(total))) + + else: + for filename, mem in sorted(mapinfo.items(), key=lambda x: -sum(x[1])): + print('{:>11} kB {:<}'.format(mem[0], filename)) + + print('=' * 30) + print('Total: {} kB'.format(total[0])) + + +if __name__ == '__main__': + main() diff --git a/tp/tp1/src/scripts/vmap.py b/tp/tp1/src/scripts/vmap.py new file mode 100755 index 0000000..ae3a643 --- /dev/null +++ b/tp/tp1/src/scripts/vmap.py @@ -0,0 +1,159 @@ +#!/usr/bin/python +# coding=utf-8 + +"""Tool to analyze and display the contents of /proc//maps""" + +import re +import itertools +import argparse +from dataclasses import dataclass + +MAPS_LINE_RE = re.compile(r""" + (?P[0-9a-f]+)-(?P[0-9a-f]+)\s+ # Address + (?P\S+)\s+ # Permissions + (?P[0-9a-f]+)\s+ # Map offset + (?P\S+)\s+ # Device node + (?P\d+)\s+ # Inode + (?P.*)\s+ # Pathname +""", re.VERBOSE) + + +def human_bytes(size): + modifier = 1 + while size > 1024: + modifier *= 1024 + size /= 1024 + return "%.1f%s" % (size, { + 1024**0: 'b', + 1024**1: 'k', + 1024**2: 'M', + 1024**3: 'G', + 1024**4: 'T', + }.get(modifier, " x%d" % modifier)) + + +@dataclass +class Record: + addr_start: int + addr_end: int + perms: str + offset: int + dev: str + inode: int + pathname: str + + @property + def size(self): + return self.addr_end - self.addr_start + + @property + def human_size(self): + return human_bytes(self.size) + + @property + def readable(self): + return self.perms[0] == "r" + + @property + def writable(self): + return self.perms[1] == "w" + + @property + def executable(self): + return self.perms[2] == "x" + + @property + def shared(self): + return self.perms[3] == "s" + + @property + def private(self): + return self.perms[3] == "p" + + @classmethod + def parse(self, pid): + records = [] + with open("/proc/%d/maps" % pid) as fd: + for line in fd: + m = MAPS_LINE_RE.match(line) + if not m: + print("Skipping: %s" % line) + continue + addr_start, addr_end, perms, offset, dev, inode, pathname = m.groups() + addr_start = int(addr_start, 16) + addr_end = int(addr_end, 16) + offset = int(offset, 16) + records.append(Record( + addr_start=addr_start, + addr_end=addr_end, + perms=perms, + offset=offset, + dev=dev, + inode=inode, + pathname=pathname, + )) + return records + + @classmethod + def aggregate(self, records, only_used=False, only_private=False): + + named_records = {} + anonymous_records = [] + for record in records: + if only_private and not record.private: + continue + if only_used and not record.readable and not record.writable and not record.shared and not record.pathname: + continue + if record.pathname: + if record.pathname in named_records: + other = named_records[record.pathname] + named_records[record.pathname] = Record( + min(record.addr_start, other.addr_start), + max(record.addr_end, other.addr_end), + perms=''.join("?" if c1 != c2 else c1 for c1, c2 in zip(record.perms, other.perms)), + offset=0, + dev='', + inode='', + pathname=record.pathname, + ) + else: + named_records[record.pathname] = record + else: + anonymous_records.append(record) + + return list(sorted( + itertools.chain(anonymous_records, named_records.values()), + key=lambda r: r.size, + reverse=True, + )) + + + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument("pid", type=int, help="Process identifier (pid)") + parser.add_argument("--only-used", "-u", action="store_true", help="Only show used pages (non readable, writable, executable and private pages)") + parser.add_argument("--only-private", "-p", action="store_true", help="Only show private pages") + args = parser.parse_args() + + records = Record.parse(args.pid) + #records = Record.aggregate(records, only_used=args.only_used, only_private=args.only_private) + + print("\t".join([ + "% 16s" % "Start of range", + "% 16s" % "End of range", + "% 12s" % "Size", + "% 4s" % "Perms", + "Path", + ])) + for record in records: + print("\t".join([ + "%016x" % record.addr_start, + "%016x" % record.addr_end, + "% 12s" % record.human_size, + "% 4s" % record.perms, + record.pathname, + ])) + + print("") + print("Total: %s" % human_bytes(sum(r.size for r in records))) diff --git a/tp/tp1/src/sum_array.c b/tp/tp1/src/sum_array.c new file mode 100644 index 0000000..7fa4b9c --- /dev/null +++ b/tp/tp1/src/sum_array.c @@ -0,0 +1,108 @@ +#include +#include +#include +#include +#include + +static inline double tstamp(void) +{ + struct timespec tv; + clock_gettime(CLOCK_REALTIME, &tv); + return tv.tv_sec + tv.tv_nsec * 1.0e-9; +} + +void shuffle(int *array, size_t n) +{ + if (n > 1) + { + size_t i; + for (i = 0; i < n - 1; i++) +// for (i = 0; i < n ; i++) + { + size_t j = i + rand() / (RAND_MAX / (n - i) + 1); +// size_t j = rand()%n; + int t = array[j]; + array[j] = array[i]; + array[i] = t; + } + } +} + +void init_access_c(int access[],size_t size) +{ + int i; + for(i=0;i