xref: /linux/tools/testing/selftests/powerpc/mm/tlbie_test.c (revision 8be98d2f2a0a262f8bf8a0bc1fdf522b3c7aab17)
193cad5f7SAneesh Kumar K.V // SPDX-License-Identifier: GPL-2.0
293cad5f7SAneesh Kumar K.V 
393cad5f7SAneesh Kumar K.V /*
493cad5f7SAneesh Kumar K.V  * Copyright 2019, Nick Piggin, Gautham R. Shenoy, Aneesh Kumar K.V, IBM Corp.
593cad5f7SAneesh Kumar K.V  */
693cad5f7SAneesh Kumar K.V 
793cad5f7SAneesh Kumar K.V /*
893cad5f7SAneesh Kumar K.V  *
993cad5f7SAneesh Kumar K.V  * Test tlbie/mtpidr race. We have 4 threads doing flush/load/compare/store
1093cad5f7SAneesh Kumar K.V  * sequence in a loop. The same threads also rung a context switch task
1193cad5f7SAneesh Kumar K.V  * that does sched_yield() in loop.
1293cad5f7SAneesh Kumar K.V  *
1393cad5f7SAneesh Kumar K.V  * The snapshot thread mark the mmap area PROT_READ in between, make a copy
1493cad5f7SAneesh Kumar K.V  * and copy it back to the original area. This helps us to detect if any
1593cad5f7SAneesh Kumar K.V  * store continued to happen after we marked the memory PROT_READ.
1693cad5f7SAneesh Kumar K.V  */
1793cad5f7SAneesh Kumar K.V 
1893cad5f7SAneesh Kumar K.V #define _GNU_SOURCE
1993cad5f7SAneesh Kumar K.V #include <stdio.h>
2093cad5f7SAneesh Kumar K.V #include <sys/mman.h>
2193cad5f7SAneesh Kumar K.V #include <sys/types.h>
2293cad5f7SAneesh Kumar K.V #include <sys/wait.h>
2393cad5f7SAneesh Kumar K.V #include <sys/ipc.h>
2493cad5f7SAneesh Kumar K.V #include <sys/shm.h>
2593cad5f7SAneesh Kumar K.V #include <sys/stat.h>
2693cad5f7SAneesh Kumar K.V #include <sys/time.h>
2793cad5f7SAneesh Kumar K.V #include <linux/futex.h>
2893cad5f7SAneesh Kumar K.V #include <unistd.h>
2993cad5f7SAneesh Kumar K.V #include <asm/unistd.h>
3093cad5f7SAneesh Kumar K.V #include <string.h>
3193cad5f7SAneesh Kumar K.V #include <stdlib.h>
3293cad5f7SAneesh Kumar K.V #include <fcntl.h>
3393cad5f7SAneesh Kumar K.V #include <sched.h>
3493cad5f7SAneesh Kumar K.V #include <time.h>
3593cad5f7SAneesh Kumar K.V #include <stdarg.h>
3693cad5f7SAneesh Kumar K.V #include <pthread.h>
3793cad5f7SAneesh Kumar K.V #include <signal.h>
3893cad5f7SAneesh Kumar K.V #include <sys/prctl.h>
3993cad5f7SAneesh Kumar K.V 
dcbf(volatile unsigned int * addr)4093cad5f7SAneesh Kumar K.V static inline void dcbf(volatile unsigned int *addr)
4193cad5f7SAneesh Kumar K.V {
4293cad5f7SAneesh Kumar K.V 	__asm__ __volatile__ ("dcbf %y0; sync" : : "Z"(*(unsigned char *)addr) : "memory");
4393cad5f7SAneesh Kumar K.V }
4493cad5f7SAneesh Kumar K.V 
err_msg(char * msg)4593cad5f7SAneesh Kumar K.V static void err_msg(char *msg)
4693cad5f7SAneesh Kumar K.V {
4793cad5f7SAneesh Kumar K.V 
4893cad5f7SAneesh Kumar K.V 	time_t now;
4993cad5f7SAneesh Kumar K.V 	time(&now);
5093cad5f7SAneesh Kumar K.V 	printf("=================================\n");
5193cad5f7SAneesh Kumar K.V 	printf("    Error: %s\n", msg);
5293cad5f7SAneesh Kumar K.V 	printf("    %s", ctime(&now));
5393cad5f7SAneesh Kumar K.V 	printf("=================================\n");
5493cad5f7SAneesh Kumar K.V 	exit(1);
5593cad5f7SAneesh Kumar K.V }
5693cad5f7SAneesh Kumar K.V 
5793cad5f7SAneesh Kumar K.V static char *map1;
5893cad5f7SAneesh Kumar K.V static char *map2;
5993cad5f7SAneesh Kumar K.V static pid_t rim_process_pid;
6093cad5f7SAneesh Kumar K.V 
6193cad5f7SAneesh Kumar K.V /*
6293cad5f7SAneesh Kumar K.V  * A "rim-sequence" is defined to be the sequence of the following
6393cad5f7SAneesh Kumar K.V  * operations performed on a memory word:
6493cad5f7SAneesh Kumar K.V  *	1) FLUSH the contents of that word.
6593cad5f7SAneesh Kumar K.V  *	2) LOAD the contents of that word.
6693cad5f7SAneesh Kumar K.V  *	3) COMPARE the contents of that word with the content that was
6793cad5f7SAneesh Kumar K.V  *	           previously stored at that word
6893cad5f7SAneesh Kumar K.V  *	4) STORE new content into that word.
6993cad5f7SAneesh Kumar K.V  *
7093cad5f7SAneesh Kumar K.V  * The threads in this test that perform the rim-sequence are termed
7193cad5f7SAneesh Kumar K.V  * as rim_threads.
7293cad5f7SAneesh Kumar K.V  */
7393cad5f7SAneesh Kumar K.V 
7493cad5f7SAneesh Kumar K.V /*
7593cad5f7SAneesh Kumar K.V  * A "corruption" is defined to be the failed COMPARE operation in a
7693cad5f7SAneesh Kumar K.V  * rim-sequence.
7793cad5f7SAneesh Kumar K.V  *
7893cad5f7SAneesh Kumar K.V  * A rim_thread that detects a corruption informs about it to all the
7993cad5f7SAneesh Kumar K.V  * other rim_threads, and the mem_snapshot thread.
8093cad5f7SAneesh Kumar K.V  */
8193cad5f7SAneesh Kumar K.V static volatile unsigned int corruption_found;
8293cad5f7SAneesh Kumar K.V 
8393cad5f7SAneesh Kumar K.V /*
8493cad5f7SAneesh Kumar K.V  * This defines the maximum number of rim_threads in this test.
8593cad5f7SAneesh Kumar K.V  *
8693cad5f7SAneesh Kumar K.V  * The THREAD_ID_BITS denote the number of bits required
8793cad5f7SAneesh Kumar K.V  * to represent the thread_ids [0..MAX_THREADS - 1].
8893cad5f7SAneesh Kumar K.V  * We are being a bit paranoid here and set it to 8 bits,
8993cad5f7SAneesh Kumar K.V  * though 6 bits suffice.
9093cad5f7SAneesh Kumar K.V  *
9193cad5f7SAneesh Kumar K.V  */
9293cad5f7SAneesh Kumar K.V #define MAX_THREADS 		64
9393cad5f7SAneesh Kumar K.V #define THREAD_ID_BITS		8
9493cad5f7SAneesh Kumar K.V #define THREAD_ID_MASK		((1 << THREAD_ID_BITS) - 1)
9593cad5f7SAneesh Kumar K.V static unsigned int rim_thread_ids[MAX_THREADS];
9693cad5f7SAneesh Kumar K.V static pthread_t rim_threads[MAX_THREADS];
9793cad5f7SAneesh Kumar K.V 
9893cad5f7SAneesh Kumar K.V 
9993cad5f7SAneesh Kumar K.V /*
10093cad5f7SAneesh Kumar K.V  * Each rim_thread works on an exclusive "chunk" of size
10193cad5f7SAneesh Kumar K.V  * RIM_CHUNK_SIZE.
10293cad5f7SAneesh Kumar K.V  *
10393cad5f7SAneesh Kumar K.V  * The ith rim_thread works on the ith chunk.
10493cad5f7SAneesh Kumar K.V  *
10593cad5f7SAneesh Kumar K.V  * The ith chunk begins at
10693cad5f7SAneesh Kumar K.V  * map1 + (i * RIM_CHUNK_SIZE)
10793cad5f7SAneesh Kumar K.V  */
10893cad5f7SAneesh Kumar K.V #define RIM_CHUNK_SIZE  	1024
10993cad5f7SAneesh Kumar K.V #define BITS_PER_BYTE 		8
11093cad5f7SAneesh Kumar K.V #define WORD_SIZE     		(sizeof(unsigned int))
11193cad5f7SAneesh Kumar K.V #define WORD_BITS		(WORD_SIZE * BITS_PER_BYTE)
11293cad5f7SAneesh Kumar K.V #define WORDS_PER_CHUNK		(RIM_CHUNK_SIZE/WORD_SIZE)
11393cad5f7SAneesh Kumar K.V 
compute_chunk_start_addr(unsigned int thread_id)11493cad5f7SAneesh Kumar K.V static inline char *compute_chunk_start_addr(unsigned int thread_id)
11593cad5f7SAneesh Kumar K.V {
11693cad5f7SAneesh Kumar K.V 	char *chunk_start;
11793cad5f7SAneesh Kumar K.V 
11893cad5f7SAneesh Kumar K.V 	chunk_start = (char *)((unsigned long)map1 +
11993cad5f7SAneesh Kumar K.V 			       (thread_id * RIM_CHUNK_SIZE));
12093cad5f7SAneesh Kumar K.V 
12193cad5f7SAneesh Kumar K.V 	return chunk_start;
12293cad5f7SAneesh Kumar K.V }
12393cad5f7SAneesh Kumar K.V 
12493cad5f7SAneesh Kumar K.V /*
12593cad5f7SAneesh Kumar K.V  * The "word-offset" of a word-aligned address inside a chunk, is
12693cad5f7SAneesh Kumar K.V  * defined to be the number of words that precede the address in that
12793cad5f7SAneesh Kumar K.V  * chunk.
12893cad5f7SAneesh Kumar K.V  *
12993cad5f7SAneesh Kumar K.V  * WORD_OFFSET_BITS denote the number of bits required to represent
13093cad5f7SAneesh Kumar K.V  * the word-offsets of all the word-aligned addresses of a chunk.
13193cad5f7SAneesh Kumar K.V  */
13293cad5f7SAneesh Kumar K.V #define WORD_OFFSET_BITS	(__builtin_ctz(WORDS_PER_CHUNK))
13393cad5f7SAneesh Kumar K.V #define WORD_OFFSET_MASK	((1 << WORD_OFFSET_BITS) - 1)
13493cad5f7SAneesh Kumar K.V 
compute_word_offset(char * start,unsigned int * addr)13593cad5f7SAneesh Kumar K.V static inline unsigned int compute_word_offset(char *start, unsigned int *addr)
13693cad5f7SAneesh Kumar K.V {
13793cad5f7SAneesh Kumar K.V 	unsigned int delta_bytes, ret;
13893cad5f7SAneesh Kumar K.V 	delta_bytes = (unsigned long)addr - (unsigned long)start;
13993cad5f7SAneesh Kumar K.V 
14093cad5f7SAneesh Kumar K.V 	ret = delta_bytes/WORD_SIZE;
14193cad5f7SAneesh Kumar K.V 
14293cad5f7SAneesh Kumar K.V 	return ret;
14393cad5f7SAneesh Kumar K.V }
14493cad5f7SAneesh Kumar K.V 
14593cad5f7SAneesh Kumar K.V /*
14693cad5f7SAneesh Kumar K.V  * A "sweep" is defined to be the sequential execution of the
14793cad5f7SAneesh Kumar K.V  * rim-sequence by a rim_thread on its chunk one word at a time,
14893cad5f7SAneesh Kumar K.V  * starting from the first word of its chunk and ending with the last
14993cad5f7SAneesh Kumar K.V  * word of its chunk.
15093cad5f7SAneesh Kumar K.V  *
15193cad5f7SAneesh Kumar K.V  * Each sweep of a rim_thread is uniquely identified by a sweep_id.
15293cad5f7SAneesh Kumar K.V  * SWEEP_ID_BITS denote the number of bits required to represent
15393cad5f7SAneesh Kumar K.V  * the sweep_ids of rim_threads.
15493cad5f7SAneesh Kumar K.V  *
15593cad5f7SAneesh Kumar K.V  * As to why SWEEP_ID_BITS are computed as a function of THREAD_ID_BITS,
15693cad5f7SAneesh Kumar K.V  * WORD_OFFSET_BITS, and WORD_BITS, see the "store-pattern" below.
15793cad5f7SAneesh Kumar K.V  */
15893cad5f7SAneesh Kumar K.V #define SWEEP_ID_BITS		(WORD_BITS - (THREAD_ID_BITS + WORD_OFFSET_BITS))
15993cad5f7SAneesh Kumar K.V #define SWEEP_ID_MASK		((1 << SWEEP_ID_BITS) - 1)
16093cad5f7SAneesh Kumar K.V 
16193cad5f7SAneesh Kumar K.V /*
16293cad5f7SAneesh Kumar K.V  * A "store-pattern" is the word-pattern that is stored into a word
16393cad5f7SAneesh Kumar K.V  * location in the 4)STORE step of the rim-sequence.
16493cad5f7SAneesh Kumar K.V  *
16593cad5f7SAneesh Kumar K.V  * In the store-pattern, we shall encode:
16693cad5f7SAneesh Kumar K.V  *
16793cad5f7SAneesh Kumar K.V  *      - The thread-id of the rim_thread performing the store
16893cad5f7SAneesh Kumar K.V  *        (The most significant THREAD_ID_BITS)
16993cad5f7SAneesh Kumar K.V  *
17093cad5f7SAneesh Kumar K.V  *      - The word-offset of the address into which the store is being
17193cad5f7SAneesh Kumar K.V  *        performed (The next WORD_OFFSET_BITS)
17293cad5f7SAneesh Kumar K.V  *
17393cad5f7SAneesh Kumar K.V  *      - The sweep_id of the current sweep in which the store is
17493cad5f7SAneesh Kumar K.V  *        being performed. (The lower SWEEP_ID_BITS)
17593cad5f7SAneesh Kumar K.V  *
17693cad5f7SAneesh Kumar K.V  * Store Pattern: 32 bits
17793cad5f7SAneesh Kumar K.V  * |------------------|--------------------|---------------------------------|
17893cad5f7SAneesh Kumar K.V  * |    Thread id     |  Word offset       |         sweep_id                |
17993cad5f7SAneesh Kumar K.V  * |------------------|--------------------|---------------------------------|
18093cad5f7SAneesh Kumar K.V  *    THREAD_ID_BITS     WORD_OFFSET_BITS          SWEEP_ID_BITS
18193cad5f7SAneesh Kumar K.V  *
18293cad5f7SAneesh Kumar K.V  * In the store pattern, the (Thread-id + Word-offset) uniquely identify the
18393cad5f7SAneesh Kumar K.V  * address to which the store is being performed i.e,
18493cad5f7SAneesh Kumar K.V  *    address == map1 +
18593cad5f7SAneesh Kumar K.V  *              (Thread-id * RIM_CHUNK_SIZE) + (Word-offset * WORD_SIZE)
18693cad5f7SAneesh Kumar K.V  *
18793cad5f7SAneesh Kumar K.V  * And the sweep_id in the store pattern identifies the time when the
18893cad5f7SAneesh Kumar K.V  * store was performed by the rim_thread.
18993cad5f7SAneesh Kumar K.V  *
19093cad5f7SAneesh Kumar K.V  * We shall use this property in the 3)COMPARE step of the
19193cad5f7SAneesh Kumar K.V  * rim-sequence.
19293cad5f7SAneesh Kumar K.V  */
19393cad5f7SAneesh Kumar K.V #define SWEEP_ID_SHIFT	0
19493cad5f7SAneesh Kumar K.V #define WORD_OFFSET_SHIFT	(SWEEP_ID_BITS)
19593cad5f7SAneesh Kumar K.V #define THREAD_ID_SHIFT		(WORD_OFFSET_BITS + SWEEP_ID_BITS)
19693cad5f7SAneesh Kumar K.V 
19793cad5f7SAneesh Kumar K.V /*
19893cad5f7SAneesh Kumar K.V  * Compute the store pattern for a given thread with id @tid, at
19993cad5f7SAneesh Kumar K.V  * location @addr in the sweep identified by @sweep_id
20093cad5f7SAneesh Kumar K.V  */
compute_store_pattern(unsigned int tid,unsigned int * addr,unsigned int sweep_id)20193cad5f7SAneesh Kumar K.V static inline unsigned int compute_store_pattern(unsigned int tid,
20293cad5f7SAneesh Kumar K.V 						 unsigned int *addr,
20393cad5f7SAneesh Kumar K.V 						 unsigned int sweep_id)
20493cad5f7SAneesh Kumar K.V {
20593cad5f7SAneesh Kumar K.V 	unsigned int ret = 0;
20693cad5f7SAneesh Kumar K.V 	char *start = compute_chunk_start_addr(tid);
20793cad5f7SAneesh Kumar K.V 	unsigned int word_offset = compute_word_offset(start, addr);
20893cad5f7SAneesh Kumar K.V 
20993cad5f7SAneesh Kumar K.V 	ret += (tid & THREAD_ID_MASK) << THREAD_ID_SHIFT;
21093cad5f7SAneesh Kumar K.V 	ret += (word_offset & WORD_OFFSET_MASK) << WORD_OFFSET_SHIFT;
21193cad5f7SAneesh Kumar K.V 	ret += (sweep_id & SWEEP_ID_MASK) << SWEEP_ID_SHIFT;
21293cad5f7SAneesh Kumar K.V 	return ret;
21393cad5f7SAneesh Kumar K.V }
21493cad5f7SAneesh Kumar K.V 
21593cad5f7SAneesh Kumar K.V /* Extract the thread-id from the given store-pattern */
extract_tid(unsigned int pattern)21693cad5f7SAneesh Kumar K.V static inline unsigned int extract_tid(unsigned int pattern)
21793cad5f7SAneesh Kumar K.V {
21893cad5f7SAneesh Kumar K.V 	unsigned int ret;
21993cad5f7SAneesh Kumar K.V 
22093cad5f7SAneesh Kumar K.V 	ret = (pattern >> THREAD_ID_SHIFT) & THREAD_ID_MASK;
22193cad5f7SAneesh Kumar K.V 	return ret;
22293cad5f7SAneesh Kumar K.V }
22393cad5f7SAneesh Kumar K.V 
22493cad5f7SAneesh Kumar K.V /* Extract the word-offset from the given store-pattern */
extract_word_offset(unsigned int pattern)22593cad5f7SAneesh Kumar K.V static inline unsigned int extract_word_offset(unsigned int pattern)
22693cad5f7SAneesh Kumar K.V {
22793cad5f7SAneesh Kumar K.V 	unsigned int ret;
22893cad5f7SAneesh Kumar K.V 
22993cad5f7SAneesh Kumar K.V 	ret = (pattern >> WORD_OFFSET_SHIFT) & WORD_OFFSET_MASK;
23093cad5f7SAneesh Kumar K.V 
23193cad5f7SAneesh Kumar K.V 	return ret;
23293cad5f7SAneesh Kumar K.V }
23393cad5f7SAneesh Kumar K.V 
23493cad5f7SAneesh Kumar K.V /* Extract the sweep-id from the given store-pattern */
extract_sweep_id(unsigned int pattern)23593cad5f7SAneesh Kumar K.V static inline unsigned int extract_sweep_id(unsigned int pattern)
23693cad5f7SAneesh Kumar K.V 
23793cad5f7SAneesh Kumar K.V {
23893cad5f7SAneesh Kumar K.V 	unsigned int ret;
23993cad5f7SAneesh Kumar K.V 
24093cad5f7SAneesh Kumar K.V 	ret = (pattern >> SWEEP_ID_SHIFT) & SWEEP_ID_MASK;
24193cad5f7SAneesh Kumar K.V 
24293cad5f7SAneesh Kumar K.V 	return ret;
24393cad5f7SAneesh Kumar K.V }
24493cad5f7SAneesh Kumar K.V 
24593cad5f7SAneesh Kumar K.V /************************************************************
24693cad5f7SAneesh Kumar K.V  *                                                          *
24793cad5f7SAneesh Kumar K.V  *          Logging the output of the verification          *
24893cad5f7SAneesh Kumar K.V  *                                                          *
24993cad5f7SAneesh Kumar K.V  ************************************************************/
25093cad5f7SAneesh Kumar K.V #define LOGDIR_NAME_SIZE 100
25193cad5f7SAneesh Kumar K.V static char logdir[LOGDIR_NAME_SIZE];
25293cad5f7SAneesh Kumar K.V 
25393cad5f7SAneesh Kumar K.V static FILE *fp[MAX_THREADS];
25493cad5f7SAneesh Kumar K.V static const char logfilename[] ="Thread-%02d-Chunk";
25593cad5f7SAneesh Kumar K.V 
start_verification_log(unsigned int tid,unsigned int * addr,unsigned int cur_sweep_id,unsigned int prev_sweep_id)25693cad5f7SAneesh Kumar K.V static inline void start_verification_log(unsigned int tid,
25793cad5f7SAneesh Kumar K.V 					  unsigned int *addr,
25893cad5f7SAneesh Kumar K.V 					  unsigned int cur_sweep_id,
25993cad5f7SAneesh Kumar K.V 					  unsigned int prev_sweep_id)
26093cad5f7SAneesh Kumar K.V {
26193cad5f7SAneesh Kumar K.V 	FILE *f;
26293cad5f7SAneesh Kumar K.V 	char logfile[30];
26393cad5f7SAneesh Kumar K.V 	char path[LOGDIR_NAME_SIZE + 30];
26493cad5f7SAneesh Kumar K.V 	char separator[2] = "/";
26593cad5f7SAneesh Kumar K.V 	char *chunk_start = compute_chunk_start_addr(tid);
26693cad5f7SAneesh Kumar K.V 	unsigned int size = RIM_CHUNK_SIZE;
26793cad5f7SAneesh Kumar K.V 
26893cad5f7SAneesh Kumar K.V 	sprintf(logfile, logfilename, tid);
26993cad5f7SAneesh Kumar K.V 	strcpy(path, logdir);
27093cad5f7SAneesh Kumar K.V 	strcat(path, separator);
27193cad5f7SAneesh Kumar K.V 	strcat(path, logfile);
27293cad5f7SAneesh Kumar K.V 	f = fopen(path, "w");
27393cad5f7SAneesh Kumar K.V 
27493cad5f7SAneesh Kumar K.V 	if (!f) {
27593cad5f7SAneesh Kumar K.V 		err_msg("Unable to create logfile\n");
27693cad5f7SAneesh Kumar K.V 	}
27793cad5f7SAneesh Kumar K.V 
27893cad5f7SAneesh Kumar K.V 	fp[tid] = f;
27993cad5f7SAneesh Kumar K.V 
28093cad5f7SAneesh Kumar K.V 	fprintf(f, "----------------------------------------------------------\n");
28193cad5f7SAneesh Kumar K.V 	fprintf(f, "PID                = %d\n", rim_process_pid);
28293cad5f7SAneesh Kumar K.V 	fprintf(f, "Thread id          = %02d\n", tid);
28393cad5f7SAneesh Kumar K.V 	fprintf(f, "Chunk Start Addr   = 0x%016lx\n", (unsigned long)chunk_start);
28493cad5f7SAneesh Kumar K.V 	fprintf(f, "Chunk Size         = %d\n", size);
28593cad5f7SAneesh Kumar K.V 	fprintf(f, "Next Store Addr    = 0x%016lx\n", (unsigned long)addr);
28693cad5f7SAneesh Kumar K.V 	fprintf(f, "Current sweep-id   = 0x%08x\n", cur_sweep_id);
28793cad5f7SAneesh Kumar K.V 	fprintf(f, "Previous sweep-id  = 0x%08x\n", prev_sweep_id);
28893cad5f7SAneesh Kumar K.V 	fprintf(f, "----------------------------------------------------------\n");
28993cad5f7SAneesh Kumar K.V }
29093cad5f7SAneesh Kumar K.V 
log_anamoly(unsigned int tid,unsigned int * addr,unsigned int expected,unsigned int observed)29193cad5f7SAneesh Kumar K.V static inline void log_anamoly(unsigned int tid, unsigned int *addr,
29293cad5f7SAneesh Kumar K.V 			       unsigned int expected, unsigned int observed)
29393cad5f7SAneesh Kumar K.V {
29493cad5f7SAneesh Kumar K.V 	FILE *f = fp[tid];
29593cad5f7SAneesh Kumar K.V 
29693cad5f7SAneesh Kumar K.V 	fprintf(f, "Thread %02d: Addr 0x%lx: Expected 0x%x, Observed 0x%x\n",
29793cad5f7SAneesh Kumar K.V 	        tid, (unsigned long)addr, expected, observed);
29893cad5f7SAneesh Kumar K.V 	fprintf(f, "Thread %02d: Expected Thread id   = %02d\n", tid, extract_tid(expected));
29993cad5f7SAneesh Kumar K.V 	fprintf(f, "Thread %02d: Observed Thread id   = %02d\n", tid, extract_tid(observed));
30093cad5f7SAneesh Kumar K.V 	fprintf(f, "Thread %02d: Expected Word offset = %03d\n", tid, extract_word_offset(expected));
30193cad5f7SAneesh Kumar K.V 	fprintf(f, "Thread %02d: Observed Word offset = %03d\n", tid, extract_word_offset(observed));
30293cad5f7SAneesh Kumar K.V 	fprintf(f, "Thread %02d: Expected sweep-id    = 0x%x\n", tid, extract_sweep_id(expected));
30393cad5f7SAneesh Kumar K.V 	fprintf(f, "Thread %02d: Observed sweep-id    = 0x%x\n", tid, extract_sweep_id(observed));
30493cad5f7SAneesh Kumar K.V 	fprintf(f, "----------------------------------------------------------\n");
30593cad5f7SAneesh Kumar K.V }
30693cad5f7SAneesh Kumar K.V 
end_verification_log(unsigned int tid,unsigned nr_anamolies)30793cad5f7SAneesh Kumar K.V static inline void end_verification_log(unsigned int tid, unsigned nr_anamolies)
30893cad5f7SAneesh Kumar K.V {
30993cad5f7SAneesh Kumar K.V 	FILE *f = fp[tid];
31093cad5f7SAneesh Kumar K.V 	char logfile[30];
31193cad5f7SAneesh Kumar K.V 	char path[LOGDIR_NAME_SIZE + 30];
31293cad5f7SAneesh Kumar K.V 	char separator[] = "/";
31393cad5f7SAneesh Kumar K.V 
31493cad5f7SAneesh Kumar K.V 	fclose(f);
31593cad5f7SAneesh Kumar K.V 
31693cad5f7SAneesh Kumar K.V 	if (nr_anamolies == 0) {
31793cad5f7SAneesh Kumar K.V 		remove(path);
31893cad5f7SAneesh Kumar K.V 		return;
31993cad5f7SAneesh Kumar K.V 	}
32093cad5f7SAneesh Kumar K.V 
32193cad5f7SAneesh Kumar K.V 	sprintf(logfile, logfilename, tid);
32293cad5f7SAneesh Kumar K.V 	strcpy(path, logdir);
32393cad5f7SAneesh Kumar K.V 	strcat(path, separator);
32493cad5f7SAneesh Kumar K.V 	strcat(path, logfile);
32593cad5f7SAneesh Kumar K.V 
32693cad5f7SAneesh Kumar K.V 	printf("Thread %02d chunk has %d corrupted words. For details check %s\n",
32793cad5f7SAneesh Kumar K.V 		tid, nr_anamolies, path);
32893cad5f7SAneesh Kumar K.V }
32993cad5f7SAneesh Kumar K.V 
33093cad5f7SAneesh Kumar K.V /*
33193cad5f7SAneesh Kumar K.V  * When a COMPARE step of a rim-sequence fails, the rim_thread informs
33293cad5f7SAneesh Kumar K.V  * everyone else via the shared_memory pointed to by
33393cad5f7SAneesh Kumar K.V  * corruption_found variable. On seeing this, every thread verifies the
33493cad5f7SAneesh Kumar K.V  * content of its chunk as follows.
33593cad5f7SAneesh Kumar K.V  *
33693cad5f7SAneesh Kumar K.V  * Suppose a thread identified with @tid was about to store (but not
33793cad5f7SAneesh Kumar K.V  * yet stored) to @next_store_addr in its current sweep identified
33893cad5f7SAneesh Kumar K.V  * @cur_sweep_id. Let @prev_sweep_id indicate the previous sweep_id.
33993cad5f7SAneesh Kumar K.V  *
34093cad5f7SAneesh Kumar K.V  * This implies that for all the addresses @addr < @next_store_addr,
34193cad5f7SAneesh Kumar K.V  * Thread @tid has already performed a store as part of its current
34293cad5f7SAneesh Kumar K.V  * sweep. Hence we expect the content of such @addr to be:
34393cad5f7SAneesh Kumar K.V  *    |-------------------------------------------------|
34493cad5f7SAneesh Kumar K.V  *    | tid   | word_offset(addr) |    cur_sweep_id     |
34593cad5f7SAneesh Kumar K.V  *    |-------------------------------------------------|
34693cad5f7SAneesh Kumar K.V  *
34793cad5f7SAneesh Kumar K.V  * Since Thread @tid is yet to perform stores on address
34893cad5f7SAneesh Kumar K.V  * @next_store_addr and above, we expect the content of such an
34993cad5f7SAneesh Kumar K.V  * address @addr to be:
35093cad5f7SAneesh Kumar K.V  *    |-------------------------------------------------|
35193cad5f7SAneesh Kumar K.V  *    | tid   | word_offset(addr) |    prev_sweep_id    |
35293cad5f7SAneesh Kumar K.V  *    |-------------------------------------------------|
35393cad5f7SAneesh Kumar K.V  *
35493cad5f7SAneesh Kumar K.V  * The verifier function @verify_chunk does this verification and logs
35593cad5f7SAneesh Kumar K.V  * any anamolies that it finds.
35693cad5f7SAneesh Kumar K.V  */
verify_chunk(unsigned int tid,unsigned int * next_store_addr,unsigned int cur_sweep_id,unsigned int prev_sweep_id)35793cad5f7SAneesh Kumar K.V static void verify_chunk(unsigned int tid, unsigned int *next_store_addr,
35893cad5f7SAneesh Kumar K.V 		  unsigned int cur_sweep_id,
35993cad5f7SAneesh Kumar K.V 		  unsigned int prev_sweep_id)
36093cad5f7SAneesh Kumar K.V {
36193cad5f7SAneesh Kumar K.V 	unsigned int *iter_ptr;
36293cad5f7SAneesh Kumar K.V 	unsigned int size = RIM_CHUNK_SIZE;
36393cad5f7SAneesh Kumar K.V 	unsigned int expected;
36493cad5f7SAneesh Kumar K.V 	unsigned int observed;
36593cad5f7SAneesh Kumar K.V 	char *chunk_start = compute_chunk_start_addr(tid);
36693cad5f7SAneesh Kumar K.V 
36793cad5f7SAneesh Kumar K.V 	int nr_anamolies = 0;
36893cad5f7SAneesh Kumar K.V 
36993cad5f7SAneesh Kumar K.V 	start_verification_log(tid, next_store_addr,
37093cad5f7SAneesh Kumar K.V 			       cur_sweep_id, prev_sweep_id);
37193cad5f7SAneesh Kumar K.V 
37293cad5f7SAneesh Kumar K.V 	for (iter_ptr = (unsigned int *)chunk_start;
37393cad5f7SAneesh Kumar K.V 	     (unsigned long)iter_ptr < (unsigned long)chunk_start + size;
37493cad5f7SAneesh Kumar K.V 	     iter_ptr++) {
37593cad5f7SAneesh Kumar K.V 		unsigned int expected_sweep_id;
37693cad5f7SAneesh Kumar K.V 
37793cad5f7SAneesh Kumar K.V 		if (iter_ptr < next_store_addr) {
37893cad5f7SAneesh Kumar K.V 			expected_sweep_id = cur_sweep_id;
37993cad5f7SAneesh Kumar K.V 		} else {
38093cad5f7SAneesh Kumar K.V 			expected_sweep_id = prev_sweep_id;
38193cad5f7SAneesh Kumar K.V 		}
38293cad5f7SAneesh Kumar K.V 
38393cad5f7SAneesh Kumar K.V 		expected = compute_store_pattern(tid, iter_ptr, expected_sweep_id);
38493cad5f7SAneesh Kumar K.V 
38593cad5f7SAneesh Kumar K.V 		dcbf((volatile unsigned int*)iter_ptr); //Flush before reading
38693cad5f7SAneesh Kumar K.V 		observed = *iter_ptr;
38793cad5f7SAneesh Kumar K.V 
38893cad5f7SAneesh Kumar K.V 	        if (observed != expected) {
38993cad5f7SAneesh Kumar K.V 			nr_anamolies++;
39093cad5f7SAneesh Kumar K.V 			log_anamoly(tid, iter_ptr, expected, observed);
39193cad5f7SAneesh Kumar K.V 		}
39293cad5f7SAneesh Kumar K.V 	}
39393cad5f7SAneesh Kumar K.V 
39493cad5f7SAneesh Kumar K.V 	end_verification_log(tid, nr_anamolies);
39593cad5f7SAneesh Kumar K.V }
39693cad5f7SAneesh Kumar K.V 
set_pthread_cpu(pthread_t th,int cpu)39793cad5f7SAneesh Kumar K.V static void set_pthread_cpu(pthread_t th, int cpu)
39893cad5f7SAneesh Kumar K.V {
39993cad5f7SAneesh Kumar K.V 	cpu_set_t run_cpu_mask;
40093cad5f7SAneesh Kumar K.V 	struct sched_param param;
40193cad5f7SAneesh Kumar K.V 
40293cad5f7SAneesh Kumar K.V 	CPU_ZERO(&run_cpu_mask);
40393cad5f7SAneesh Kumar K.V 	CPU_SET(cpu, &run_cpu_mask);
40493cad5f7SAneesh Kumar K.V 	pthread_setaffinity_np(th, sizeof(cpu_set_t), &run_cpu_mask);
40593cad5f7SAneesh Kumar K.V 
40693cad5f7SAneesh Kumar K.V 	param.sched_priority = 1;
40793cad5f7SAneesh Kumar K.V 	if (0 && sched_setscheduler(0, SCHED_FIFO, &param) == -1) {
40893cad5f7SAneesh Kumar K.V 		/* haven't reproduced with this setting, it kills random preemption which may be a factor */
40993cad5f7SAneesh Kumar K.V 		fprintf(stderr, "could not set SCHED_FIFO, run as root?\n");
41093cad5f7SAneesh Kumar K.V 	}
41193cad5f7SAneesh Kumar K.V }
41293cad5f7SAneesh Kumar K.V 
set_mycpu(int cpu)41393cad5f7SAneesh Kumar K.V static void set_mycpu(int cpu)
41493cad5f7SAneesh Kumar K.V {
41593cad5f7SAneesh Kumar K.V 	cpu_set_t run_cpu_mask;
41693cad5f7SAneesh Kumar K.V 	struct sched_param param;
41793cad5f7SAneesh Kumar K.V 
41893cad5f7SAneesh Kumar K.V 	CPU_ZERO(&run_cpu_mask);
41993cad5f7SAneesh Kumar K.V 	CPU_SET(cpu, &run_cpu_mask);
42093cad5f7SAneesh Kumar K.V 	sched_setaffinity(0, sizeof(cpu_set_t), &run_cpu_mask);
42193cad5f7SAneesh Kumar K.V 
42293cad5f7SAneesh Kumar K.V 	param.sched_priority = 1;
42393cad5f7SAneesh Kumar K.V 	if (0 && sched_setscheduler(0, SCHED_FIFO, &param) == -1) {
42493cad5f7SAneesh Kumar K.V 		fprintf(stderr, "could not set SCHED_FIFO, run as root?\n");
42593cad5f7SAneesh Kumar K.V 	}
42693cad5f7SAneesh Kumar K.V }
42793cad5f7SAneesh Kumar K.V 
42893cad5f7SAneesh Kumar K.V static volatile int segv_wait;
42993cad5f7SAneesh Kumar K.V 
segv_handler(int signo,siginfo_t * info,void * extra)43093cad5f7SAneesh Kumar K.V static void segv_handler(int signo, siginfo_t *info, void *extra)
43193cad5f7SAneesh Kumar K.V {
43293cad5f7SAneesh Kumar K.V 	while (segv_wait) {
43393cad5f7SAneesh Kumar K.V 		sched_yield();
43493cad5f7SAneesh Kumar K.V 	}
43593cad5f7SAneesh Kumar K.V 
43693cad5f7SAneesh Kumar K.V }
43793cad5f7SAneesh Kumar K.V 
set_segv_handler(void)43893cad5f7SAneesh Kumar K.V static void set_segv_handler(void)
43993cad5f7SAneesh Kumar K.V {
44093cad5f7SAneesh Kumar K.V 	struct sigaction sa;
44193cad5f7SAneesh Kumar K.V 
44293cad5f7SAneesh Kumar K.V 	sa.sa_flags = SA_SIGINFO;
44393cad5f7SAneesh Kumar K.V 	sa.sa_sigaction = segv_handler;
44493cad5f7SAneesh Kumar K.V 
44593cad5f7SAneesh Kumar K.V 	if (sigaction(SIGSEGV, &sa, NULL) == -1) {
44693cad5f7SAneesh Kumar K.V 		perror("sigaction");
44793cad5f7SAneesh Kumar K.V 		exit(EXIT_FAILURE);
44893cad5f7SAneesh Kumar K.V 	}
44993cad5f7SAneesh Kumar K.V }
45093cad5f7SAneesh Kumar K.V 
45193cad5f7SAneesh Kumar K.V int timeout = 0;
45293cad5f7SAneesh Kumar K.V /*
45393cad5f7SAneesh Kumar K.V  * This function is executed by every rim_thread.
45493cad5f7SAneesh Kumar K.V  *
45593cad5f7SAneesh Kumar K.V  * This function performs sweeps over the exclusive chunks of the
45693cad5f7SAneesh Kumar K.V  * rim_threads executing the rim-sequence one word at a time.
45793cad5f7SAneesh Kumar K.V  */
rim_fn(void * arg)45893cad5f7SAneesh Kumar K.V static void *rim_fn(void *arg)
45993cad5f7SAneesh Kumar K.V {
46093cad5f7SAneesh Kumar K.V 	unsigned int tid = *((unsigned int *)arg);
46193cad5f7SAneesh Kumar K.V 
46293cad5f7SAneesh Kumar K.V 	int size = RIM_CHUNK_SIZE;
46393cad5f7SAneesh Kumar K.V 	char *chunk_start = compute_chunk_start_addr(tid);
46493cad5f7SAneesh Kumar K.V 
46593cad5f7SAneesh Kumar K.V 	unsigned int prev_sweep_id;
46693cad5f7SAneesh Kumar K.V 	unsigned int cur_sweep_id = 0;
46793cad5f7SAneesh Kumar K.V 
46893cad5f7SAneesh Kumar K.V 	/* word access */
46993cad5f7SAneesh Kumar K.V 	unsigned int pattern = cur_sweep_id;
47093cad5f7SAneesh Kumar K.V 	unsigned int *pattern_ptr = &pattern;
47193cad5f7SAneesh Kumar K.V 	unsigned int *w_ptr, read_data;
47293cad5f7SAneesh Kumar K.V 
47393cad5f7SAneesh Kumar K.V 	set_segv_handler();
47493cad5f7SAneesh Kumar K.V 
47593cad5f7SAneesh Kumar K.V 	/*
47693cad5f7SAneesh Kumar K.V 	 * Let us initialize the chunk:
47793cad5f7SAneesh Kumar K.V 	 *
47893cad5f7SAneesh Kumar K.V 	 * Each word-aligned address addr in the chunk,
47993cad5f7SAneesh Kumar K.V 	 * is initialized to :
48093cad5f7SAneesh Kumar K.V 	 *    |-------------------------------------------------|
48193cad5f7SAneesh Kumar K.V 	 *    | tid   | word_offset(addr) |         0           |
48293cad5f7SAneesh Kumar K.V 	 *    |-------------------------------------------------|
48393cad5f7SAneesh Kumar K.V 	 */
48493cad5f7SAneesh Kumar K.V 	for (w_ptr = (unsigned int *)chunk_start;
48593cad5f7SAneesh Kumar K.V 	     (unsigned long)w_ptr < (unsigned long)(chunk_start) + size;
48693cad5f7SAneesh Kumar K.V 	     w_ptr++) {
48793cad5f7SAneesh Kumar K.V 
48893cad5f7SAneesh Kumar K.V 		*pattern_ptr = compute_store_pattern(tid, w_ptr, cur_sweep_id);
48993cad5f7SAneesh Kumar K.V 		*w_ptr = *pattern_ptr;
49093cad5f7SAneesh Kumar K.V 	}
49193cad5f7SAneesh Kumar K.V 
49293cad5f7SAneesh Kumar K.V 	while (!corruption_found && !timeout) {
49393cad5f7SAneesh Kumar K.V 		prev_sweep_id = cur_sweep_id;
49493cad5f7SAneesh Kumar K.V 		cur_sweep_id = cur_sweep_id + 1;
49593cad5f7SAneesh Kumar K.V 
49693cad5f7SAneesh Kumar K.V 		for (w_ptr = (unsigned int *)chunk_start;
49793cad5f7SAneesh Kumar K.V 		     (unsigned long)w_ptr < (unsigned long)(chunk_start) + size;
49893cad5f7SAneesh Kumar K.V 		     w_ptr++)  {
49993cad5f7SAneesh Kumar K.V 			unsigned int old_pattern;
50093cad5f7SAneesh Kumar K.V 
50193cad5f7SAneesh Kumar K.V 			/*
50293cad5f7SAneesh Kumar K.V 			 * Compute the pattern that we would have
50393cad5f7SAneesh Kumar K.V 			 * stored at this location in the previous
50493cad5f7SAneesh Kumar K.V 			 * sweep.
50593cad5f7SAneesh Kumar K.V 			 */
50693cad5f7SAneesh Kumar K.V 			old_pattern = compute_store_pattern(tid, w_ptr, prev_sweep_id);
50793cad5f7SAneesh Kumar K.V 
50893cad5f7SAneesh Kumar K.V 			/*
50993cad5f7SAneesh Kumar K.V 			 * FLUSH:Ensure that we flush the contents of
51093cad5f7SAneesh Kumar K.V 			 *       the cache before loading
51193cad5f7SAneesh Kumar K.V 			 */
51293cad5f7SAneesh Kumar K.V 			dcbf((volatile unsigned int*)w_ptr); //Flush
51393cad5f7SAneesh Kumar K.V 
51493cad5f7SAneesh Kumar K.V 			/* LOAD: Read the value */
51593cad5f7SAneesh Kumar K.V 			read_data = *w_ptr; //Load
51693cad5f7SAneesh Kumar K.V 
51793cad5f7SAneesh Kumar K.V 			/*
51893cad5f7SAneesh Kumar K.V 			 * COMPARE: Is it the same as what we had stored
51993cad5f7SAneesh Kumar K.V 			 *          in the previous sweep ? It better be!
52093cad5f7SAneesh Kumar K.V 			 */
52193cad5f7SAneesh Kumar K.V 			if (read_data != old_pattern) {
52293cad5f7SAneesh Kumar K.V 				/* No it isn't! Tell everyone */
52393cad5f7SAneesh Kumar K.V 				corruption_found = 1;
52493cad5f7SAneesh Kumar K.V 			}
52593cad5f7SAneesh Kumar K.V 
52693cad5f7SAneesh Kumar K.V 			/*
52793cad5f7SAneesh Kumar K.V 			 * Before performing a store, let us check if
52893cad5f7SAneesh Kumar K.V 			 * any rim_thread has found a corruption.
52993cad5f7SAneesh Kumar K.V 			 */
53093cad5f7SAneesh Kumar K.V 			if (corruption_found || timeout) {
53193cad5f7SAneesh Kumar K.V 				/*
53293cad5f7SAneesh Kumar K.V 				 * Yes. Someone (including us!) has found
53393cad5f7SAneesh Kumar K.V 				 * a corruption :(
53493cad5f7SAneesh Kumar K.V 				 *
53593cad5f7SAneesh Kumar K.V 				 * Let us verify that our chunk is
53693cad5f7SAneesh Kumar K.V 				 * correct.
53793cad5f7SAneesh Kumar K.V 				 */
53893cad5f7SAneesh Kumar K.V 				/* But first, let us allow the dust to settle down! */
53993cad5f7SAneesh Kumar K.V 				verify_chunk(tid, w_ptr, cur_sweep_id, prev_sweep_id);
54093cad5f7SAneesh Kumar K.V 
54193cad5f7SAneesh Kumar K.V 				return 0;
54293cad5f7SAneesh Kumar K.V 			}
54393cad5f7SAneesh Kumar K.V 
54493cad5f7SAneesh Kumar K.V 			/*
54593cad5f7SAneesh Kumar K.V 			 * Compute the new pattern that we are going
54693cad5f7SAneesh Kumar K.V 			 * to write to this location
54793cad5f7SAneesh Kumar K.V 			 */
54893cad5f7SAneesh Kumar K.V 			*pattern_ptr = compute_store_pattern(tid, w_ptr, cur_sweep_id);
54993cad5f7SAneesh Kumar K.V 
55093cad5f7SAneesh Kumar K.V 			/*
55193cad5f7SAneesh Kumar K.V 			 * STORE: Now let us write this pattern into
55293cad5f7SAneesh Kumar K.V 			 *        the location
55393cad5f7SAneesh Kumar K.V 			 */
55493cad5f7SAneesh Kumar K.V 			*w_ptr = *pattern_ptr;
55593cad5f7SAneesh Kumar K.V 		}
55693cad5f7SAneesh Kumar K.V 	}
55793cad5f7SAneesh Kumar K.V 
55893cad5f7SAneesh Kumar K.V 	return NULL;
55993cad5f7SAneesh Kumar K.V }
56093cad5f7SAneesh Kumar K.V 
56193cad5f7SAneesh Kumar K.V 
56293cad5f7SAneesh Kumar K.V static unsigned long start_cpu = 0;
56393cad5f7SAneesh Kumar K.V static unsigned long nrthreads = 4;
56493cad5f7SAneesh Kumar K.V 
56593cad5f7SAneesh Kumar K.V static pthread_t mem_snapshot_thread;
56693cad5f7SAneesh Kumar K.V 
mem_snapshot_fn(void * arg)56793cad5f7SAneesh Kumar K.V static void *mem_snapshot_fn(void *arg)
56893cad5f7SAneesh Kumar K.V {
56993cad5f7SAneesh Kumar K.V 	int page_size = getpagesize();
57093cad5f7SAneesh Kumar K.V 	size_t size = page_size;
57193cad5f7SAneesh Kumar K.V 	void *tmp = malloc(size);
57293cad5f7SAneesh Kumar K.V 
57393cad5f7SAneesh Kumar K.V 	while (!corruption_found && !timeout) {
57493cad5f7SAneesh Kumar K.V 		/* Stop memory migration once corruption is found */
57593cad5f7SAneesh Kumar K.V 		segv_wait = 1;
57693cad5f7SAneesh Kumar K.V 
57793cad5f7SAneesh Kumar K.V 		mprotect(map1, size, PROT_READ);
57893cad5f7SAneesh Kumar K.V 
57993cad5f7SAneesh Kumar K.V 		/*
58093cad5f7SAneesh Kumar K.V 		 * Load from the working alias (map1). Loading from map2
58193cad5f7SAneesh Kumar K.V 		 * also fails.
58293cad5f7SAneesh Kumar K.V 		 */
58393cad5f7SAneesh Kumar K.V 		memcpy(tmp, map1, size);
58493cad5f7SAneesh Kumar K.V 
58593cad5f7SAneesh Kumar K.V 		/*
58693cad5f7SAneesh Kumar K.V 		 * Stores must go via map2 which has write permissions, but
58793cad5f7SAneesh Kumar K.V 		 * the corrupted data tends to be seen in the snapshot buffer,
58893cad5f7SAneesh Kumar K.V 		 * so corruption does not appear to be introduced at the
58993cad5f7SAneesh Kumar K.V 		 * copy-back via map2 alias here.
59093cad5f7SAneesh Kumar K.V 		 */
59193cad5f7SAneesh Kumar K.V 		memcpy(map2, tmp, size);
59293cad5f7SAneesh Kumar K.V 		/*
59393cad5f7SAneesh Kumar K.V 		 * Before releasing other threads, must ensure the copy
59493cad5f7SAneesh Kumar K.V 		 * back to
59593cad5f7SAneesh Kumar K.V 		 */
59693cad5f7SAneesh Kumar K.V 		asm volatile("sync" ::: "memory");
59793cad5f7SAneesh Kumar K.V 		mprotect(map1, size, PROT_READ|PROT_WRITE);
59893cad5f7SAneesh Kumar K.V 		asm volatile("sync" ::: "memory");
59993cad5f7SAneesh Kumar K.V 		segv_wait = 0;
60093cad5f7SAneesh Kumar K.V 
60193cad5f7SAneesh Kumar K.V 		usleep(1); /* This value makes a big difference */
60293cad5f7SAneesh Kumar K.V 	}
60393cad5f7SAneesh Kumar K.V 
60493cad5f7SAneesh Kumar K.V 	return 0;
60593cad5f7SAneesh Kumar K.V }
60693cad5f7SAneesh Kumar K.V 
alrm_sighandler(int sig)60793cad5f7SAneesh Kumar K.V void alrm_sighandler(int sig)
60893cad5f7SAneesh Kumar K.V {
60993cad5f7SAneesh Kumar K.V 	timeout = 1;
61093cad5f7SAneesh Kumar K.V }
61193cad5f7SAneesh Kumar K.V 
main(int argc,char * argv[])61293cad5f7SAneesh Kumar K.V int main(int argc, char *argv[])
61393cad5f7SAneesh Kumar K.V {
61493cad5f7SAneesh Kumar K.V 	int c;
61593cad5f7SAneesh Kumar K.V 	int page_size = getpagesize();
61693cad5f7SAneesh Kumar K.V 	time_t now;
61793cad5f7SAneesh Kumar K.V 	int i, dir_error;
61893cad5f7SAneesh Kumar K.V 	pthread_attr_t attr;
61993cad5f7SAneesh Kumar K.V 	key_t shm_key = (key_t) getpid();
62093cad5f7SAneesh Kumar K.V 	int shmid, run_time = 20 * 60;
62193cad5f7SAneesh Kumar K.V 	struct sigaction sa_alrm;
62293cad5f7SAneesh Kumar K.V 
62393cad5f7SAneesh Kumar K.V 	snprintf(logdir, LOGDIR_NAME_SIZE,
62493cad5f7SAneesh Kumar K.V 		 "/tmp/logdir-%u", (unsigned int)getpid());
62593cad5f7SAneesh Kumar K.V 	while ((c = getopt(argc, argv, "r:hn:l:t:")) != -1) {
62693cad5f7SAneesh Kumar K.V 		switch(c) {
62793cad5f7SAneesh Kumar K.V 		case 'r':
62893cad5f7SAneesh Kumar K.V 			start_cpu = strtoul(optarg, NULL, 10);
62993cad5f7SAneesh Kumar K.V 			break;
63093cad5f7SAneesh Kumar K.V 		case 'h':
63193cad5f7SAneesh Kumar K.V 			printf("%s [-r <start_cpu>] [-n <nrthreads>] [-l <logdir>] [-t <timeout>]\n", argv[0]);
63293cad5f7SAneesh Kumar K.V 			exit(0);
63393cad5f7SAneesh Kumar K.V 			break;
63493cad5f7SAneesh Kumar K.V 		case 'n':
63593cad5f7SAneesh Kumar K.V 			nrthreads = strtoul(optarg, NULL, 10);
63693cad5f7SAneesh Kumar K.V 			break;
63793cad5f7SAneesh Kumar K.V 		case 'l':
638*5b216ea1SDesnes A. Nunes do Rosario 			strncpy(logdir, optarg, LOGDIR_NAME_SIZE - 1);
63993cad5f7SAneesh Kumar K.V 			break;
64093cad5f7SAneesh Kumar K.V 		case 't':
64193cad5f7SAneesh Kumar K.V 			run_time = strtoul(optarg, NULL, 10);
64293cad5f7SAneesh Kumar K.V 			break;
64393cad5f7SAneesh Kumar K.V 		default:
64493cad5f7SAneesh Kumar K.V 			printf("invalid option\n");
64593cad5f7SAneesh Kumar K.V 			exit(0);
64693cad5f7SAneesh Kumar K.V 			break;
64793cad5f7SAneesh Kumar K.V 		}
64893cad5f7SAneesh Kumar K.V 	}
64993cad5f7SAneesh Kumar K.V 
65093cad5f7SAneesh Kumar K.V 	if (nrthreads > MAX_THREADS)
65193cad5f7SAneesh Kumar K.V 		nrthreads = MAX_THREADS;
65293cad5f7SAneesh Kumar K.V 
65393cad5f7SAneesh Kumar K.V 	shmid = shmget(shm_key, page_size, IPC_CREAT|0666);
65493cad5f7SAneesh Kumar K.V 	if (shmid < 0) {
65593cad5f7SAneesh Kumar K.V 		err_msg("Failed shmget\n");
65693cad5f7SAneesh Kumar K.V 	}
65793cad5f7SAneesh Kumar K.V 
65893cad5f7SAneesh Kumar K.V 	map1 = shmat(shmid, NULL, 0);
65993cad5f7SAneesh Kumar K.V 	if (map1 == (void *) -1) {
66093cad5f7SAneesh Kumar K.V 		err_msg("Failed shmat");
66193cad5f7SAneesh Kumar K.V 	}
66293cad5f7SAneesh Kumar K.V 
66393cad5f7SAneesh Kumar K.V 	map2 = shmat(shmid, NULL, 0);
66493cad5f7SAneesh Kumar K.V 	if (map2 == (void *) -1) {
66593cad5f7SAneesh Kumar K.V 		err_msg("Failed shmat");
66693cad5f7SAneesh Kumar K.V 	}
66793cad5f7SAneesh Kumar K.V 
66893cad5f7SAneesh Kumar K.V 	dir_error = mkdir(logdir, 0755);
66993cad5f7SAneesh Kumar K.V 
67093cad5f7SAneesh Kumar K.V 	if (dir_error) {
67193cad5f7SAneesh Kumar K.V 		err_msg("Failed mkdir");
67293cad5f7SAneesh Kumar K.V 	}
67393cad5f7SAneesh Kumar K.V 
67493cad5f7SAneesh Kumar K.V 	printf("start_cpu list:%lu\n", start_cpu);
67593cad5f7SAneesh Kumar K.V 	printf("number of worker threads:%lu + 1 snapshot thread\n", nrthreads);
67693cad5f7SAneesh Kumar K.V 	printf("Allocated address:0x%016lx + secondary map:0x%016lx\n", (unsigned long)map1, (unsigned long)map2);
67793cad5f7SAneesh Kumar K.V 	printf("logdir at : %s\n", logdir);
67893cad5f7SAneesh Kumar K.V 	printf("Timeout: %d seconds\n", run_time);
67993cad5f7SAneesh Kumar K.V 
68093cad5f7SAneesh Kumar K.V 	time(&now);
68193cad5f7SAneesh Kumar K.V 	printf("=================================\n");
68293cad5f7SAneesh Kumar K.V 	printf("     Starting Test\n");
68393cad5f7SAneesh Kumar K.V 	printf("     %s", ctime(&now));
68493cad5f7SAneesh Kumar K.V 	printf("=================================\n");
68593cad5f7SAneesh Kumar K.V 
68693cad5f7SAneesh Kumar K.V 	for (i = 0; i < nrthreads; i++) {
68793cad5f7SAneesh Kumar K.V 		if (1 && !fork()) {
68893cad5f7SAneesh Kumar K.V 			prctl(PR_SET_PDEATHSIG, SIGKILL);
68993cad5f7SAneesh Kumar K.V 			set_mycpu(start_cpu + i);
69093cad5f7SAneesh Kumar K.V 			for (;;)
69193cad5f7SAneesh Kumar K.V 				sched_yield();
69293cad5f7SAneesh Kumar K.V 			exit(0);
69393cad5f7SAneesh Kumar K.V 		}
69493cad5f7SAneesh Kumar K.V 	}
69593cad5f7SAneesh Kumar K.V 
69693cad5f7SAneesh Kumar K.V 
69793cad5f7SAneesh Kumar K.V 	sa_alrm.sa_handler = &alrm_sighandler;
69893cad5f7SAneesh Kumar K.V 	sigemptyset(&sa_alrm.sa_mask);
69993cad5f7SAneesh Kumar K.V 	sa_alrm.sa_flags = 0;
70093cad5f7SAneesh Kumar K.V 
70193cad5f7SAneesh Kumar K.V 	if (sigaction(SIGALRM, &sa_alrm, 0) == -1) {
70293cad5f7SAneesh Kumar K.V 		err_msg("Failed signal handler registration\n");
70393cad5f7SAneesh Kumar K.V 	}
70493cad5f7SAneesh Kumar K.V 
70593cad5f7SAneesh Kumar K.V 	alarm(run_time);
70693cad5f7SAneesh Kumar K.V 
70793cad5f7SAneesh Kumar K.V 	pthread_attr_init(&attr);
70893cad5f7SAneesh Kumar K.V 	for (i = 0; i < nrthreads; i++) {
70993cad5f7SAneesh Kumar K.V 		rim_thread_ids[i] = i;
71093cad5f7SAneesh Kumar K.V 		pthread_create(&rim_threads[i], &attr, rim_fn, &rim_thread_ids[i]);
71193cad5f7SAneesh Kumar K.V 		set_pthread_cpu(rim_threads[i], start_cpu + i);
71293cad5f7SAneesh Kumar K.V 	}
71393cad5f7SAneesh Kumar K.V 
71493cad5f7SAneesh Kumar K.V 	pthread_create(&mem_snapshot_thread, &attr, mem_snapshot_fn, map1);
71593cad5f7SAneesh Kumar K.V 	set_pthread_cpu(mem_snapshot_thread, start_cpu + i);
71693cad5f7SAneesh Kumar K.V 
71793cad5f7SAneesh Kumar K.V 
71893cad5f7SAneesh Kumar K.V 	pthread_join(mem_snapshot_thread, NULL);
71993cad5f7SAneesh Kumar K.V 	for (i = 0; i < nrthreads; i++) {
72093cad5f7SAneesh Kumar K.V 		pthread_join(rim_threads[i], NULL);
72193cad5f7SAneesh Kumar K.V 	}
72293cad5f7SAneesh Kumar K.V 
72393cad5f7SAneesh Kumar K.V 	if (!timeout) {
72493cad5f7SAneesh Kumar K.V 		time(&now);
72593cad5f7SAneesh Kumar K.V 		printf("=================================\n");
72693cad5f7SAneesh Kumar K.V 		printf("      Data Corruption Detected\n");
72793cad5f7SAneesh Kumar K.V 		printf("      %s", ctime(&now));
72893cad5f7SAneesh Kumar K.V 		printf("      See logfiles in %s\n", logdir);
72993cad5f7SAneesh Kumar K.V 		printf("=================================\n");
73093cad5f7SAneesh Kumar K.V 		return 1;
73193cad5f7SAneesh Kumar K.V 	}
73293cad5f7SAneesh Kumar K.V 	return 0;
73393cad5f7SAneesh Kumar K.V }
734