Add jumbo events
This commit is contained in:
		
							parent
							
								
									77a879c0a0
								
							
						
					
					
						commit
						d7c81b3048
					
				
							
								
								
									
										12
									
								
								dump.c
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								dump.c
									
									
									
									
									
								
							| @ -55,7 +55,7 @@ void emit(struct ovni_stream *stream, struct ovni_ev *ev) | |||||||
| 
 | 
 | ||||||
| 	printf("%d.%d.%d %c %c %c % 20lu % 15ld ", | 	printf("%d.%d.%d %c %c %c % 20lu % 15ld ", | ||||||
| 			stream->loom, stream->proc, stream->tid, | 			stream->loom, stream->proc, stream->tid, | ||||||
| 			ev->model, ev->class, ev->value, clock, delta); | 			ev->header.model, ev->header.class, ev->header.value, clock, delta); | ||||||
| 
 | 
 | ||||||
| 	payloadsize = ovni_payload_size(ev); | 	payloadsize = ovni_payload_size(ev); | ||||||
| 	for(i=0; i<payloadsize; i++) | 	for(i=0; i<payloadsize; i++) | ||||||
| @ -97,7 +97,7 @@ void dump_events(struct ovni_trace *trace) | |||||||
| 			if(!stream->active) | 			if(!stream->active) | ||||||
| 				continue; | 				continue; | ||||||
| 
 | 
 | ||||||
| 			ev = &stream->last; | 			ev = stream->cur_ev; | ||||||
| 			if(f < 0 || ovni_ev_get_clock(ev) < minclock) | 			if(f < 0 || ovni_ev_get_clock(ev) < minclock) | ||||||
| 			{ | 			{ | ||||||
| 				f = i; | 				f = i; | ||||||
| @ -112,16 +112,16 @@ void dump_events(struct ovni_trace *trace) | |||||||
| 
 | 
 | ||||||
| 		stream = &trace->stream[f]; | 		stream = &trace->stream[f]; | ||||||
| 
 | 
 | ||||||
| 		if(lastclock > ovni_ev_get_clock(&stream->last)) | 		if(lastclock > ovni_ev_get_clock(stream->cur_ev)) | ||||||
| 		{ | 		{ | ||||||
| 			fprintf(stdout, "warning: backwards jump in time %lu -> %lu\n", | 			fprintf(stdout, "warning: backwards jump in time %lu -> %lu\n", | ||||||
| 					lastclock, ovni_ev_get_clock(&stream->last)); | 					lastclock, ovni_ev_get_clock(stream->cur_ev)); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		/* Emit current event */ | 		/* Emit current event */ | ||||||
| 		emit(stream, &stream->last); | 		emit(stream, stream->cur_ev); | ||||||
| 
 | 
 | ||||||
| 		lastclock = ovni_ev_get_clock(&stream->last); | 		lastclock = ovni_ev_get_clock(stream->cur_ev); | ||||||
| 
 | 
 | ||||||
| 		/* Read the next one */ | 		/* Read the next one */ | ||||||
| 		ovni_load_next_event(stream); | 		ovni_load_next_event(stream); | ||||||
|  | |||||||
							
								
								
									
										39
									
								
								emu.c
									
									
									
									
									
								
							
							
						
						
									
										39
									
								
								emu.c
									
									
									
									
									
								
							| @ -29,7 +29,7 @@ emit_ev(struct ovni_stream *stream, struct ovni_ev *ev) | |||||||
| 
 | 
 | ||||||
| 	dbg("%d.%d.%d %c %c %c % 20lu % 15ld ", | 	dbg("%d.%d.%d %c %c %c % 20lu % 15ld ", | ||||||
| 			stream->loom, stream->proc, stream->tid, | 			stream->loom, stream->proc, stream->tid, | ||||||
| 			ev->model, ev->class, ev->value, clock, delta); | 			ev->header.model, ev->header.class, ev->header.value, clock, delta); | ||||||
| 
 | 
 | ||||||
| 	payloadsize = ovni_payload_size(ev); | 	payloadsize = ovni_payload_size(ev); | ||||||
| 	for(i=0; i<payloadsize; i++) | 	for(i=0; i<payloadsize; i++) | ||||||
| @ -47,27 +47,6 @@ emu_emit(struct ovni_emu *emu) | |||||||
| 	emit_ev(emu->cur_stream, emu->cur_ev); | 	emit_ev(emu->cur_stream, emu->cur_ev); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void |  | ||||||
| load_first_event(struct ovni_stream *stream) |  | ||||||
| { |  | ||||||
| 	int i; |  | ||||||
| 	size_t n; |  | ||||||
| 	struct ovni_ev *ev; |  | ||||||
| 
 |  | ||||||
| 	if(!stream->active) |  | ||||||
| 		return; |  | ||||||
| 
 |  | ||||||
| 	ev = &stream->last; |  | ||||||
| 	if((n = fread(ev, sizeof(*ev), 1, stream->f)) != 1) |  | ||||||
| 	{ |  | ||||||
| 		//fprintf(stderr, "failed to read an event, n=%ld\n", n);
 |  | ||||||
| 		stream->active = 0; |  | ||||||
| 		return; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	stream->active = 1; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| struct ovni_ethread * | struct ovni_ethread * | ||||||
| find_thread(struct ovni_eproc *proc, pid_t tid) | find_thread(struct ovni_eproc *proc, pid_t tid) | ||||||
| { | { | ||||||
| @ -89,7 +68,7 @@ hook_pre(struct ovni_emu *emu) | |||||||
| { | { | ||||||
| 	//emu_emit(emu);
 | 	//emu_emit(emu);
 | ||||||
| 
 | 
 | ||||||
| 	switch(emu->cur_ev->model) | 	switch(emu->cur_ev->header.model) | ||||||
| 	{ | 	{ | ||||||
| 		case 'O': hook_pre_ovni(emu); break; | 		case 'O': hook_pre_ovni(emu); break; | ||||||
| 		case 'V': hook_pre_nosv(emu); break; | 		case 'V': hook_pre_nosv(emu); break; | ||||||
| @ -104,7 +83,7 @@ hook_view(struct ovni_emu *emu) | |||||||
| { | { | ||||||
| 	//emu_emit(emu);
 | 	//emu_emit(emu);
 | ||||||
| 
 | 
 | ||||||
| 	switch(emu->cur_ev->model) | 	switch(emu->cur_ev->header.model) | ||||||
| 	{ | 	{ | ||||||
| 		case 'O': hook_view_ovni(emu); break; | 		case 'O': hook_view_ovni(emu); break; | ||||||
| 		case 'V': hook_view_nosv(emu); break; | 		case 'V': hook_view_nosv(emu); break; | ||||||
| @ -119,7 +98,7 @@ hook_post(struct ovni_emu *emu) | |||||||
| { | { | ||||||
| 	//emu_emit(emu);
 | 	//emu_emit(emu);
 | ||||||
| 
 | 
 | ||||||
| 	switch(emu->cur_ev->model) | 	switch(emu->cur_ev->header.model) | ||||||
| 	{ | 	{ | ||||||
| 		case 'O': hook_post_ovni(emu); break; | 		case 'O': hook_post_ovni(emu); break; | ||||||
| 		default: | 		default: | ||||||
| @ -132,7 +111,7 @@ static void | |||||||
| set_current(struct ovni_emu *emu, struct ovni_stream *stream) | set_current(struct ovni_emu *emu, struct ovni_stream *stream) | ||||||
| { | { | ||||||
| 	emu->cur_stream = stream; | 	emu->cur_stream = stream; | ||||||
| 	emu->cur_ev = &stream->last; | 	emu->cur_ev = stream->cur_ev; | ||||||
| 	emu->cur_loom = &emu->trace.loom[stream->loom]; | 	emu->cur_loom = &emu->trace.loom[stream->loom]; | ||||||
| 	emu->cur_proc = &emu->cur_loom->proc[stream->proc]; | 	emu->cur_proc = &emu->cur_loom->proc[stream->proc]; | ||||||
| 	emu->cur_thread = &emu->cur_proc->thread[stream->thread]; | 	emu->cur_thread = &emu->cur_proc->thread[stream->thread]; | ||||||
| @ -163,7 +142,7 @@ next_event(struct ovni_emu *emu) | |||||||
| 		if(!stream->active) | 		if(!stream->active) | ||||||
| 			continue; | 			continue; | ||||||
| 
 | 
 | ||||||
| 		ev = &stream->last; | 		ev = stream->cur_ev; | ||||||
| 		if(f < 0 || ovni_ev_get_clock(ev) < minclock) | 		if(f < 0 || ovni_ev_get_clock(ev) < minclock) | ||||||
| 		{ | 		{ | ||||||
| 			f = i; | 			f = i; | ||||||
| @ -179,13 +158,13 @@ next_event(struct ovni_emu *emu) | |||||||
| 
 | 
 | ||||||
| 	set_current(emu, stream); | 	set_current(emu, stream); | ||||||
| 
 | 
 | ||||||
| 	if(emu->lastclock > ovni_ev_get_clock(&stream->last)) | 	if(emu->lastclock > ovni_ev_get_clock(stream->cur_ev)) | ||||||
| 	{ | 	{ | ||||||
| 		fprintf(stdout, "warning: backwards jump in time %lu -> %lu\n", | 		fprintf(stdout, "warning: backwards jump in time %lu -> %lu\n", | ||||||
| 				emu->lastclock, ovni_ev_get_clock(&stream->last)); | 				emu->lastclock, ovni_ev_get_clock(stream->cur_ev)); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	emu->lastclock = ovni_ev_get_clock(&stream->last); | 	emu->lastclock = ovni_ev_get_clock(stream->cur_ev); | ||||||
| 
 | 
 | ||||||
| 	if(t0 < 0) | 	if(t0 < 0) | ||||||
| 		t0 = emu->lastclock; | 		t0 = emu->lastclock; | ||||||
|  | |||||||
							
								
								
									
										15
									
								
								emu.h
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								emu.h
									
									
									
									
									
								
							| @ -25,7 +25,6 @@ enum ethread_state { | |||||||
| 	TH_ST_DEAD, | 	TH_ST_DEAD, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| enum nosv_task_state { | enum nosv_task_state { | ||||||
| 	TASK_ST_CREATED, | 	TASK_ST_CREATED, | ||||||
| 	TASK_ST_RUNNING, | 	TASK_ST_RUNNING, | ||||||
| @ -45,17 +44,17 @@ struct nosv_task { | |||||||
| 
 | 
 | ||||||
| struct nosv_task_type { | struct nosv_task_type { | ||||||
| 	int id; | 	int id; | ||||||
|  | 	const char *label; | ||||||
| 	UT_hash_handle hh; | 	UT_hash_handle hh; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| /* State of each emulated thread */ | /* State of each emulated thread */ | ||||||
| struct ovni_ethread { | struct ovni_ethread { | ||||||
| 	/* Emulated thread tid */ | 	/* Emulated thread tid */ | ||||||
| 	pid_t tid; | 	pid_t tid; | ||||||
| 
 | 
 | ||||||
| 	/* Stream file */ | 	/* Stream fd */ | ||||||
| 	FILE *f; | 	int stream_fd; | ||||||
| 
 | 
 | ||||||
| 	enum ethread_state state; | 	enum ethread_state state; | ||||||
| 
 | 
 | ||||||
| @ -95,14 +94,17 @@ struct ovni_loom { | |||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| struct ovni_stream { | struct ovni_stream { | ||||||
| 	FILE *f; | 	uint8_t *buf; | ||||||
|  | 	size_t size; | ||||||
|  | 	size_t offset; | ||||||
|  | 
 | ||||||
| 	int tid; | 	int tid; | ||||||
| 	int thread; | 	int thread; | ||||||
| 	int proc; | 	int proc; | ||||||
| 	int loom; | 	int loom; | ||||||
| 	int loaded; | 	int loaded; | ||||||
| 	int active; | 	int active; | ||||||
| 	struct ovni_ev last; | 	struct ovni_ev *cur_ev; | ||||||
| 	uint64_t lastclock; | 	uint64_t lastclock; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| @ -142,7 +144,6 @@ struct ovni_cpu { | |||||||
| 	struct ovni_ethread *thread[OVNI_MAX_THR]; | 	struct ovni_ethread *thread[OVNI_MAX_THR]; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| struct ovni_emu { | struct ovni_emu { | ||||||
| 	struct ovni_trace trace; | 	struct ovni_trace trace; | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										35
									
								
								emu_nosv.c
									
									
									
									
									
								
							
							
						
						
									
										35
									
								
								emu_nosv.c
									
									
									
									
									
								
							| @ -148,7 +148,7 @@ static void | |||||||
| pre_task(struct ovni_emu *emu) | pre_task(struct ovni_emu *emu) | ||||||
| { | { | ||||||
| 	emu_emit(emu); | 	emu_emit(emu); | ||||||
| 	switch(emu->cur_ev->value) | 	switch(emu->cur_ev->header.value) | ||||||
| 	{ | 	{ | ||||||
| 		case 'c': pre_task_create(emu); break; | 		case 'c': pre_task_create(emu); break; | ||||||
| 		case 'x': pre_task_execute(emu); break; | 		case 'x': pre_task_execute(emu); break; | ||||||
| @ -165,16 +165,27 @@ static void | |||||||
| pre_type_create(struct ovni_emu *emu) | pre_type_create(struct ovni_emu *emu) | ||||||
| { | { | ||||||
| 	struct nosv_task_type *type, *p = NULL; | 	struct nosv_task_type *type, *p = NULL; | ||||||
| 	int typeid; | 	uint8_t *data; | ||||||
|  | 	uint32_t *typeid; | ||||||
|  | 	const char *label; | ||||||
| 
 | 
 | ||||||
| 	typeid = emu->cur_ev->payload.i32[0]; | 	if((emu->cur_ev->header.flags & OVNI_EV_JUMBO) == 0) | ||||||
|  | 	{ | ||||||
|  | 		err("expecting a jumbo event\n"); | ||||||
|  | 		abort(); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	data = &emu->cur_ev->payload.jumbo.data[0]; | ||||||
|  | 	typeid = (uint32_t *) data; | ||||||
|  | 	data += sizeof(*typeid); | ||||||
|  | 	label = (const char *) data; | ||||||
| 
 | 
 | ||||||
| 	/* Ensure the type id is new */ | 	/* Ensure the type id is new */ | ||||||
| 	HASH_FIND_INT(types, &typeid, type); | 	HASH_FIND_INT(types, typeid, type); | ||||||
| 
 | 
 | ||||||
| 	if(type != NULL) | 	if(type != NULL) | ||||||
| 	{ | 	{ | ||||||
| 		err("A task type with id %d already exists\n", p->id); | 		err("A task type with id %d already exists\n", *typeid); | ||||||
| 		abort(); | 		abort(); | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
| @ -186,18 +197,20 @@ pre_type_create(struct ovni_emu *emu) | |||||||
| 		abort(); | 		abort(); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	type->id = typeid; | 	type->id = *typeid; | ||||||
|  | 	type->label = label; | ||||||
| 
 | 
 | ||||||
| 	/* Add the new task type to the hash table */ | 	/* Add the new task type to the hash table */ | ||||||
| 	HASH_ADD_INT(types, id, type); | 	HASH_ADD_INT(types, id, type); | ||||||
| 
 | 
 | ||||||
| 	dbg("new task type created id=%d\n", type->id); | 	dbg("new task type created id=%d label=%s\n", type->id, | ||||||
|  | 			type->label); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void | static void | ||||||
| pre_type(struct ovni_emu *emu) | pre_type(struct ovni_emu *emu) | ||||||
| { | { | ||||||
| 	switch(emu->cur_ev->value) | 	switch(emu->cur_ev->header.value) | ||||||
| 	{ | 	{ | ||||||
| 		case 'c': pre_type_create(emu); break; | 		case 'c': pre_type_create(emu); break; | ||||||
| 		default: | 		default: | ||||||
| @ -209,7 +222,7 @@ void | |||||||
| hook_pre_nosv(struct ovni_emu *emu) | hook_pre_nosv(struct ovni_emu *emu) | ||||||
| { | { | ||||||
| 	dbg("pre nosv\n"); | 	dbg("pre nosv\n"); | ||||||
| 	switch(emu->cur_ev->class) | 	switch(emu->cur_ev->header.class) | ||||||
| 	{ | 	{ | ||||||
| 		case 'T': pre_task(emu); break; | 		case 'T': pre_task(emu); break; | ||||||
| 		case 'Y': pre_type(emu); break; | 		case 'Y': pre_type(emu); break; | ||||||
| @ -266,7 +279,7 @@ emit_task_end(struct ovni_emu *emu) | |||||||
| static void | static void | ||||||
| emit_task(struct ovni_emu *emu) | emit_task(struct ovni_emu *emu) | ||||||
| { | { | ||||||
| 	switch(emu->cur_ev->value) | 	switch(emu->cur_ev->header.value) | ||||||
| 	{ | 	{ | ||||||
| 		case 'c': emit_task_create(emu); break; | 		case 'c': emit_task_create(emu); break; | ||||||
| 		case 'x': emit_task_execute(emu); break; | 		case 'x': emit_task_execute(emu); break; | ||||||
| @ -282,7 +295,7 @@ void | |||||||
| hook_view_nosv(struct ovni_emu *emu) | hook_view_nosv(struct ovni_emu *emu) | ||||||
| { | { | ||||||
| 	dbg("pre nosv\n"); | 	dbg("pre nosv\n"); | ||||||
| 	switch(emu->cur_ev->class) | 	switch(emu->cur_ev->header.class) | ||||||
| 	{ | 	{ | ||||||
| 		case 'T': emit_task(emu); break; | 		case 'T': emit_task(emu); break; | ||||||
| 		default: | 		default: | ||||||
|  | |||||||
							
								
								
									
										18
									
								
								emu_ovni.c
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								emu_ovni.c
									
									
									
									
									
								
							| @ -158,7 +158,7 @@ ev_thread(struct ovni_emu *emu) | |||||||
| 	cpu = thread->cpu; | 	cpu = thread->cpu; | ||||||
| 	ev = emu->cur_ev; | 	ev = emu->cur_ev; | ||||||
| 
 | 
 | ||||||
| 	switch(ev->value) | 	switch(ev->header.value) | ||||||
| 	{ | 	{ | ||||||
| 		case 'c': /* create */ | 		case 'c': /* create */ | ||||||
| 			dbg("thread %d creates a new thread at cpu=%d with args=%x %x\n", | 			dbg("thread %d creates a new thread at cpu=%d with args=%x %x\n", | ||||||
| @ -231,13 +231,13 @@ static void | |||||||
| ev_affinity(struct ovni_emu *emu) | ev_affinity(struct ovni_emu *emu) | ||||||
| { | { | ||||||
| 	//emu_emit(emu);
 | 	//emu_emit(emu);
 | ||||||
| 	switch(emu->cur_ev->value) | 	switch(emu->cur_ev->header.value) | ||||||
| 	{ | 	{ | ||||||
| 		case 's': ev_affinity_set(emu); break; | 		case 's': ev_affinity_set(emu); break; | ||||||
| 		case 'r': ev_affinity_remote(emu); break; | 		case 'r': ev_affinity_remote(emu); break; | ||||||
| 		default: | 		default: | ||||||
| 			dbg("unknown affinity event value %c\n", | 			dbg("unknown affinity event value %c\n", | ||||||
| 					emu->cur_ev->value); | 					emu->cur_ev->header.value); | ||||||
| 			break; | 			break; | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| @ -294,13 +294,13 @@ ev_cpu_id(struct ovni_emu *emu) | |||||||
| static void | static void | ||||||
| ev_cpu(struct ovni_emu *emu) | ev_cpu(struct ovni_emu *emu) | ||||||
| { | { | ||||||
| 	switch(emu->cur_ev->value) | 	switch(emu->cur_ev->header.value) | ||||||
| 	{ | 	{ | ||||||
| 		case 'n': ev_cpu_count(emu); break; | 		case 'n': ev_cpu_count(emu); break; | ||||||
| 		case 'i': ev_cpu_id(emu); break; | 		case 'i': ev_cpu_id(emu); break; | ||||||
| 		default: | 		default: | ||||||
| 			dbg("unknown cpu event value %c\n", | 			dbg("unknown cpu event value %c\n", | ||||||
| 					emu->cur_ev->value); | 					emu->cur_ev->header.value); | ||||||
| 			break; | 			break; | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| @ -310,15 +310,15 @@ hook_pre_ovni(struct ovni_emu *emu) | |||||||
| { | { | ||||||
| 	//emu_emit(emu);
 | 	//emu_emit(emu);
 | ||||||
| 
 | 
 | ||||||
| 	switch(emu->cur_ev->class) | 	switch(emu->cur_ev->header.class) | ||||||
| 	{ | 	{ | ||||||
| 		case 'H': ev_thread(emu); break; | 		case 'H': ev_thread(emu); break; | ||||||
| 		case 'A': ev_affinity(emu); break; | 		case 'A': ev_affinity(emu); break; | ||||||
| 		case 'C': ev_cpu(emu); break; | 		case 'C': ev_cpu(emu); break; | ||||||
| 		case 'B': dbg("burst %c\n", emu->cur_ev->value); break; | 		case 'B': dbg("burst %c\n", emu->cur_ev->header.value); break; | ||||||
| 		default: | 		default: | ||||||
| 			dbg("unknown ovni event class %c\n", | 			dbg("unknown ovni event class %c\n", | ||||||
| 					emu->cur_ev->class); | 					emu->cur_ev->header.class); | ||||||
| 			break; | 			break; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| @ -367,7 +367,7 @@ emit: | |||||||
| void | void | ||||||
| hook_view_ovni(struct ovni_emu *emu) | hook_view_ovni(struct ovni_emu *emu) | ||||||
| { | { | ||||||
| 	switch(emu->cur_ev->class) | 	switch(emu->cur_ev->header.class) | ||||||
| 	{ | 	{ | ||||||
| 		case 'H': | 		case 'H': | ||||||
| 		case 'A': | 		case 'A': | ||||||
|  | |||||||
							
								
								
									
										229
									
								
								ovni.c
									
									
									
									
									
								
							
							
						
						
									
										229
									
								
								ovni.c
									
									
									
									
									
								
							| @ -9,6 +9,7 @@ | |||||||
| #include <linux/limits.h> | #include <linux/limits.h> | ||||||
| #include <errno.h> | #include <errno.h> | ||||||
| #include <sys/stat.h> | #include <sys/stat.h> | ||||||
|  | #include <sys/mman.h> | ||||||
| #include <stdatomic.h> | #include <stdatomic.h> | ||||||
| #include <assert.h> | #include <assert.h> | ||||||
| #include <unistd.h> | #include <unistd.h> | ||||||
| @ -284,8 +285,8 @@ flush_evbuf() | |||||||
| static void | static void | ||||||
| ovni_ev_set_clock(struct ovni_ev *ev) | ovni_ev_set_clock(struct ovni_ev *ev) | ||||||
| { | { | ||||||
| 	ev->clock_lo = (uint32_t) (rthread.clockvalue & 0xffffffff); | 	ev->header.clock_lo = (uint32_t) (rthread.clockvalue & 0xffffffff); | ||||||
| 	ev->clock_hi = (uint16_t) ((rthread.clockvalue >> 32) & 0xffff); | 	ev->header.clock_hi = (uint16_t) ((rthread.clockvalue >> 32) & 0xffff); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| uint64_t | uint64_t | ||||||
| @ -293,16 +294,22 @@ ovni_ev_get_clock(struct ovni_ev *ev) | |||||||
| { | { | ||||||
| 	uint64_t clock; | 	uint64_t clock; | ||||||
| 
 | 
 | ||||||
| 	clock = ((uint64_t) ev->clock_hi) << 32 | ((uint64_t) ev->clock_lo); | 	clock = ((uint64_t) ev->header.clock_hi) << 32 | ((uint64_t) ev->header.clock_lo); | ||||||
| 	return clock; | 	return clock; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void | void | ||||||
| ovni_ev_set_mcv(struct ovni_ev *ev, char *mcv) | ovni_ev_set_mcv(struct ovni_ev *ev, char *mcv) | ||||||
| { | { | ||||||
| 	ev->model = mcv[0]; | 	ev->header.model = mcv[0]; | ||||||
| 	ev->class = mcv[1]; | 	ev->header.class = mcv[1]; | ||||||
| 	ev->value = mcv[2]; | 	ev->header.value = mcv[2]; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static size_t | ||||||
|  | get_jumbo_payload_size(struct ovni_ev *ev) | ||||||
|  | { | ||||||
|  | 	return sizeof(ev->payload.jumbo.size) + ev->payload.jumbo.size; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int | int | ||||||
| @ -310,7 +317,10 @@ ovni_payload_size(struct ovni_ev *ev) | |||||||
| { | { | ||||||
| 	int size; | 	int size; | ||||||
| 
 | 
 | ||||||
| 	size = ev->flags & 0x0f; | 	if(ev->header.flags & OVNI_EV_JUMBO) | ||||||
|  | 		return get_jumbo_payload_size(ev); | ||||||
|  | 
 | ||||||
|  | 	size = ev->header.flags & 0x0f; | ||||||
| 
 | 
 | ||||||
| 	if(size == 0) | 	if(size == 0) | ||||||
| 		return 0; | 		return 0; | ||||||
| @ -327,6 +337,9 @@ ovni_payload_add(struct ovni_ev *ev, uint8_t *buf, int size) | |||||||
| { | { | ||||||
| 	int payload_size; | 	int payload_size; | ||||||
| 
 | 
 | ||||||
|  | 	assert((ev->header.flags & OVNI_EV_JUMBO) == 0); | ||||||
|  | 	assert(size >= 2); | ||||||
|  | 
 | ||||||
| 	payload_size = ovni_payload_size(ev); | 	payload_size = ovni_payload_size(ev); | ||||||
| 
 | 
 | ||||||
| 	/* Ensure we have room */ | 	/* Ensure we have room */ | ||||||
| @ -335,37 +348,17 @@ ovni_payload_add(struct ovni_ev *ev, uint8_t *buf, int size) | |||||||
| 	memcpy(&ev->payload.u8[payload_size], buf, size); | 	memcpy(&ev->payload.u8[payload_size], buf, size); | ||||||
| 	payload_size += size; | 	payload_size += size; | ||||||
| 
 | 
 | ||||||
| 	ev->flags = ev->flags & 0xf0 | (payload_size-1) & 0x0f; | 	ev->header.flags = ev->header.flags & 0xf0 | (payload_size-1) & 0x0f; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int | int | ||||||
| ovni_ev_size(struct ovni_ev *ev) | ovni_ev_size(struct ovni_ev *ev) | ||||||
| { | { | ||||||
| 	return sizeof(*ev) - sizeof(ev->payload) + | 	return sizeof(ev->header) + ovni_payload_size(ev); | ||||||
| 		ovni_payload_size(ev); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| static void | static void | ||||||
| ovni_ev_add(struct ovni_ev *ev) | ovni_ev_add(struct ovni_ev *ev); | ||||||
| { |  | ||||||
| 	int size;	 |  | ||||||
| 
 |  | ||||||
| 	ovni_ev_set_clock(ev); |  | ||||||
| 	 |  | ||||||
| 	size = ovni_ev_size(ev); |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 	memcpy(&rthread.evbuf[rthread.evlen], ev, size); |  | ||||||
| 	rthread.evlen += size; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void |  | ||||||
| ovni_ev(struct ovni_ev *ev) |  | ||||||
| { |  | ||||||
| 	ovni_ev_set_clock(ev); |  | ||||||
| 	ovni_ev_add(ev); |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| int | int | ||||||
| ovni_flush() | ovni_flush() | ||||||
| @ -393,6 +386,79 @@ ovni_flush() | |||||||
| 	return ret; | 	return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void | ||||||
|  | ovni_ev_add_jumbo(struct ovni_ev *ev, uint8_t *buf, uint32_t bufsize) | ||||||
|  | { | ||||||
|  | 	size_t evsize, totalsize; | ||||||
|  | 
 | ||||||
|  | 	assert(ovni_payload_size(ev) == 0); | ||||||
|  | 
 | ||||||
|  | 	ovni_payload_add(ev, (uint8_t *) &bufsize, sizeof(bufsize)); | ||||||
|  | 	evsize = ovni_ev_size(ev); | ||||||
|  | 
 | ||||||
|  | 	totalsize = evsize + bufsize; | ||||||
|  | 
 | ||||||
|  | 	/* Check if the event fits or flush first otherwise */ | ||||||
|  | 	if(rthread.evlen + totalsize >= OVNI_MAX_EV_BUF) | ||||||
|  | 		ovni_flush(); | ||||||
|  | 
 | ||||||
|  | 	/* Se the jumbo flag here, so we capture the previous evsize
 | ||||||
|  | 	 * properly, ignoring the jumbo buffer */ | ||||||
|  | 	ev->header.flags |= OVNI_EV_JUMBO; | ||||||
|  | 
 | ||||||
|  | 	memcpy(&rthread.evbuf[rthread.evlen], ev, evsize); | ||||||
|  | 	rthread.evlen += evsize; | ||||||
|  | 	memcpy(&rthread.evbuf[rthread.evlen], buf, bufsize); | ||||||
|  | 	rthread.evlen += bufsize; | ||||||
|  | 
 | ||||||
|  | 	assert(rthread.evlen < OVNI_MAX_EV_BUF); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | static void | ||||||
|  | ovni_ev_add(struct ovni_ev *ev) | ||||||
|  | { | ||||||
|  | 	int size;	 | ||||||
|  | 
 | ||||||
|  | 	size = ovni_ev_size(ev); | ||||||
|  | 
 | ||||||
|  | 	/* Check if the event fits or flush first otherwise */ | ||||||
|  | 	if(rthread.evlen + size >= OVNI_MAX_EV_BUF) | ||||||
|  | 		ovni_flush(); | ||||||
|  | 
 | ||||||
|  | 	memcpy(&rthread.evbuf[rthread.evlen], ev, size); | ||||||
|  | 	rthread.evlen += size; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void | ||||||
|  | ovni_ev_jumbo(struct ovni_ev *ev, uint8_t *buf, uint32_t bufsize) | ||||||
|  | { | ||||||
|  | 	ovni_ev_set_clock(ev); | ||||||
|  | 	ovni_ev_add_jumbo(ev, buf, bufsize); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void | ||||||
|  | ovni_ev(struct ovni_ev *ev) | ||||||
|  | { | ||||||
|  | 	ovni_ev_set_clock(ev); | ||||||
|  | 	ovni_ev_add(ev); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int | ||||||
|  | load_thread(struct ovni_ethread *thread, int tid, char *filepath) | ||||||
|  | { | ||||||
|  | 	thread->tid = tid; | ||||||
|  | 	thread->stream_fd = open(filepath, O_RDONLY); | ||||||
|  | 
 | ||||||
|  | 	if(thread->stream_fd == -1) | ||||||
|  | 	{ | ||||||
|  | 		perror("open"); | ||||||
|  | 		return -1; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	thread->state = TH_ST_UNKNOWN; | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| static int | static int | ||||||
| load_proc(struct ovni_eproc *proc, char *procdir) | load_proc(struct ovni_eproc *proc, char *procdir) | ||||||
| @ -425,20 +491,12 @@ load_proc(struct ovni_eproc *proc, char *procdir) | |||||||
| 			return -1; | 			return -1; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | 		sprintf(path, "%s/%s", procdir, dirent->d_name); | ||||||
| 
 | 
 | ||||||
| 		thread = &proc->thread[proc->nthreads++]; | 		thread = &proc->thread[proc->nthreads++]; | ||||||
| 		thread->tid = atoi(p); |  | ||||||
| 
 | 
 | ||||||
| 		sprintf(path, "%s/%s", procdir, dirent->d_name); | 		if(load_thread(thread, atoi(p), path) != 0) | ||||||
| 		thread->f = fopen(path, "r"); |  | ||||||
| 		thread->state = TH_ST_UNKNOWN; |  | ||||||
| 
 |  | ||||||
| 		if(thread->f == NULL) |  | ||||||
| 		{ |  | ||||||
| 			fprintf(stderr, "fopen %s failed: %s\n", |  | ||||||
| 					path, strerror(errno)); |  | ||||||
| 			return -1; | 			return -1; | ||||||
| 		} |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	closedir(dir); | 	closedir(dir); | ||||||
| @ -503,6 +561,30 @@ ovni_load_trace(struct ovni_trace *trace, char *tracedir) | |||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static int | ||||||
|  | load_stream_buf(struct ovni_stream *stream, struct ovni_ethread *thread) | ||||||
|  | { | ||||||
|  | 	struct stat st; | ||||||
|  | 
 | ||||||
|  | 	if(fstat(thread->stream_fd, &st) < 0) | ||||||
|  | 	{ | ||||||
|  | 		perror("fstat"); | ||||||
|  | 		return -1; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	stream->size = st.st_size; | ||||||
|  | 	stream->buf = mmap(NULL, stream->size, PROT_READ, MAP_SHARED, | ||||||
|  | 			thread->stream_fd, 0); | ||||||
|  | 
 | ||||||
|  | 	if(stream->buf == MAP_FAILED) | ||||||
|  | 	{ | ||||||
|  | 		perror("mmap"); | ||||||
|  | 		return -1; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /* Populates the streams in a single array */ | /* Populates the streams in a single array */ | ||||||
| int | int | ||||||
| ovni_load_streams(struct ovni_trace *trace) | ovni_load_streams(struct ovni_trace *trace) | ||||||
| @ -549,13 +631,20 @@ ovni_load_streams(struct ovni_trace *trace) | |||||||
| 				thread = &proc->thread[k]; | 				thread = &proc->thread[k]; | ||||||
| 				stream = &trace->stream[s++]; | 				stream = &trace->stream[s++]; | ||||||
| 
 | 
 | ||||||
| 				stream->f = thread->f; | 				if(load_stream_buf(stream, thread) != 0) | ||||||
|  | 				{ | ||||||
|  | 					err("load_stream_buf failed\n"); | ||||||
|  | 					return -1; | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
| 				stream->tid = thread->tid; | 				stream->tid = thread->tid; | ||||||
| 				stream->thread = k; | 				stream->thread = k; | ||||||
| 				stream->proc = j; | 				stream->proc = j; | ||||||
| 				stream->loom = i; | 				stream->loom = i; | ||||||
| 				stream->active = 1; | 				stream->active = 1; | ||||||
| 				stream->lastclock = 0; | 				stream->lastclock = 0; | ||||||
|  | 				stream->offset = 0; | ||||||
|  | 				stream->cur_ev = NULL; | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| @ -569,45 +658,51 @@ ovni_free_streams(struct ovni_trace *trace) | |||||||
| 	free(trace->stream); | 	free(trace->stream); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void | int | ||||||
| ovni_load_next_event(struct ovni_stream *stream) | ovni_load_next_event(struct ovni_stream *stream) | ||||||
| { | { | ||||||
| 	int i; | 	int i; | ||||||
| 	size_t n, size; | 	size_t n, size; | ||||||
| 	struct ovni_ev *ev; |  | ||||||
| 	uint8_t flags; | 	uint8_t flags; | ||||||
| 
 | 
 | ||||||
| 	if(!stream->active) | 	if(stream->active == 0) | ||||||
| 		return; |  | ||||||
| 
 |  | ||||||
| 	ev = &stream->last; |  | ||||||
| 	if((n = fread(&ev->flags, sizeof(ev->flags), 1, stream->f)) != 1) |  | ||||||
| 	{ | 	{ | ||||||
| 		dbg("stream is empty\n"); | 		dbg("stream is inactive, cannot load more events\n"); | ||||||
| 		stream->active = 0; | 		return -1; | ||||||
| 		return; |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	//dbg("flags = %d\n", ev->flags);
 | 	if(stream->cur_ev == NULL) | ||||||
| 
 |  | ||||||
| 	size = ovni_ev_size(ev) - sizeof(ev->flags); |  | ||||||
| 	//dbg("ev size = %d\n", size);
 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 	/* Clean payload from previous event */ |  | ||||||
| 	memset(&ev->payload, 0, sizeof(ev->payload)); |  | ||||||
| 
 |  | ||||||
| 	if((n = fread(((uint8_t *) ev) + sizeof(ev->flags), 1, size, stream->f)) != size) |  | ||||||
| 	{ | 	{ | ||||||
| 		err("warning: garbage found at the end of the stream\n"); | 		stream->cur_ev = (struct ovni_ev *) stream->buf; | ||||||
| 		stream->active = 0; | 		stream->offset = 0; | ||||||
| 		return; | 		dbg("first event\n"); | ||||||
|  | 		goto out; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	//printf("advancing offset %ld bytes\n", ovni_ev_size(stream->cur_ev));
 | ||||||
|  | 	stream->offset += ovni_ev_size(stream->cur_ev); | ||||||
|  | 
 | ||||||
|  | 	/* We have reached the end */ | ||||||
|  | 	if(stream->offset == stream->size) | ||||||
|  | 	{ | ||||||
|  | 		stream->active = 0; | ||||||
|  | 		dbg("stream runs out of events\n"); | ||||||
|  | 		return -1; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/* It cannot overflow, otherwise we are reading garbage */ | ||||||
|  | 	assert(stream->offset < stream->size); | ||||||
|  | 
 | ||||||
|  | 	stream->cur_ev = (struct ovni_ev *) &stream->buf[stream->offset]; | ||||||
|  | 
 | ||||||
|  | out: | ||||||
|  | 
 | ||||||
|  | 	//dbg("---------\n");
 | ||||||
|  | 	//dbg("ev size = %d\n", ovni_ev_size(stream->cur_ev));
 | ||||||
|  | 	//dbg("ev flags = %02x\n", stream->cur_ev->header.flags);
 | ||||||
| 	//dbg("loaded next event:\n");
 | 	//dbg("loaded next event:\n");
 | ||||||
| 	//hexdump((uint8_t *) ev, ovni_ev_size(ev));
 | 	//hexdump((uint8_t *) stream->cur_ev, ovni_ev_size(stream->cur_ev));
 | ||||||
| 	//dbg("---------\n");
 | 	//dbg("---------\n");
 | ||||||
| 
 | 
 | ||||||
| 	stream->active = 1; | 	return 0; | ||||||
| 
 |  | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										44
									
								
								ovni.h
									
									
									
									
									
								
							
							
						
						
									
										44
									
								
								ovni.h
									
									
									
									
									
								
							| @ -18,25 +18,46 @@ | |||||||
| 
 | 
 | ||||||
| /* ----------------------- common ------------------------ */ | /* ----------------------- common ------------------------ */ | ||||||
| 
 | 
 | ||||||
| union __attribute__((__packed__)) ovni_ev_payload { | enum ovni_ev_flags { | ||||||
| 	uint8_t u8[16]; | 	OVNI_EV_JUMBO = 0x10, | ||||||
| 	int8_t i8[16]; |  | ||||||
| 	uint16_t u16[8]; |  | ||||||
| 	int16_t i16[8]; |  | ||||||
| 	uint32_t u32[4]; |  | ||||||
| 	int32_t i32[4]; |  | ||||||
| 	uint64_t u64[2]; |  | ||||||
| 	int64_t i64[2]; |  | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| struct __attribute__((__packed__)) ovni_ev { | struct __attribute__((__packed__)) ovni_jumbo_payload { | ||||||
|  | 	uint32_t size; | ||||||
|  | 	uint8_t data[1]; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | union __attribute__((__packed__)) ovni_ev_payload { | ||||||
|  | 
 | ||||||
|  | 	int8_t i8[16]; | ||||||
|  | 	int16_t i16[8]; | ||||||
|  | 	int32_t i32[4]; | ||||||
|  | 	int64_t i64[2]; | ||||||
|  | 
 | ||||||
|  | 	uint8_t u8[16]; | ||||||
|  | 	uint16_t u16[8]; | ||||||
|  | 	uint32_t u32[4]; | ||||||
|  | 	uint64_t u64[2]; | ||||||
|  | 
 | ||||||
|  | 	struct ovni_jumbo_payload jumbo; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct __attribute__((__packed__)) ovni_ev_header { | ||||||
| 	/* first 4 bits reserved, last 4 for payload size */ | 	/* first 4 bits reserved, last 4 for payload size */ | ||||||
| 	uint8_t flags; | 	uint8_t flags; | ||||||
| 	uint8_t model; | 	uint8_t model; | ||||||
| 	uint8_t class; | 	uint8_t class; | ||||||
| 	uint8_t value; | 	uint8_t value; | ||||||
| 	uint16_t clock_hi; |  | ||||||
| 	uint32_t clock_lo; | 	uint32_t clock_lo; | ||||||
|  | 	uint16_t clock_hi; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct __attribute__((__packed__)) ovni_ev { | ||||||
|  | 	struct ovni_ev_header header; | ||||||
|  | 
 | ||||||
|  | 	/* The payload size may vary depending on the ev type:
 | ||||||
|  | 	 *   - normal: 0, or 2 to 16 bytes | ||||||
|  | 	 *   - jumbo: 0 to 2^32 - 1 bytes */ | ||||||
| 	union ovni_ev_payload payload; | 	union ovni_ev_payload payload; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| @ -100,6 +121,7 @@ int ovni_payload_size(struct ovni_ev *ev); | |||||||
| 
 | 
 | ||||||
| /* Set the current clock in the event and queue it */ | /* Set the current clock in the event and queue it */ | ||||||
| void ovni_ev(struct ovni_ev *ev); | void ovni_ev(struct ovni_ev *ev); | ||||||
|  | void ovni_ev_jumbo(struct ovni_ev *ev, uint8_t *buf, uint32_t bufsize); | ||||||
| 
 | 
 | ||||||
| int ovni_flush(); | int ovni_flush(); | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										10
									
								
								ovni2prv.c
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								ovni2prv.c
									
									
									
									
									
								
							| @ -31,7 +31,7 @@ void emit(struct ovni_stream *stream, struct ovni_ev *ev) | |||||||
| 	//2:0:1:1:7:1542091:6400025:1
 | 	//2:0:1:1:7:1542091:6400025:1
 | ||||||
| 	//2:0:1:1:7:1542091:6400017:0
 | 	//2:0:1:1:7:1542091:6400017:0
 | ||||||
| 
 | 
 | ||||||
| 	printf("2:0:1:1:%d:%ld:%d:%d\n", stream->thread+1, delta, ev->class, ev->value); | 	printf("2:0:1:1:%d:%ld:%d:%d\n", stream->thread+1, delta, ev->header.class, ev->header.value); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void dump_events(struct ovni_trace *trace) | void dump_events(struct ovni_trace *trace) | ||||||
| @ -63,7 +63,7 @@ void dump_events(struct ovni_trace *trace) | |||||||
| 			if(!stream->active) | 			if(!stream->active) | ||||||
| 				continue; | 				continue; | ||||||
| 
 | 
 | ||||||
| 			ev = &stream->last; | 			ev = stream->cur_ev; | ||||||
| 			if(f < 0 || ovni_ev_get_clock(ev) < minclock) | 			if(f < 0 || ovni_ev_get_clock(ev) < minclock) | ||||||
| 			{ | 			{ | ||||||
| 				f = i; | 				f = i; | ||||||
| @ -78,15 +78,15 @@ void dump_events(struct ovni_trace *trace) | |||||||
| 
 | 
 | ||||||
| 		stream = &trace->stream[f]; | 		stream = &trace->stream[f]; | ||||||
| 
 | 
 | ||||||
| 		if(lastclock >= ovni_ev_get_clock(&stream->last)) | 		if(lastclock >= ovni_ev_get_clock(stream->cur_ev)) | ||||||
| 		{ | 		{ | ||||||
| 			fprintf(stderr, "warning: backwards jump in time\n"); | 			fprintf(stderr, "warning: backwards jump in time\n"); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		/* Emit current event */ | 		/* Emit current event */ | ||||||
| 		emit(stream, &stream->last); | 		emit(stream, stream->cur_ev); | ||||||
| 
 | 
 | ||||||
| 		lastclock = ovni_ev_get_clock(&stream->last); | 		lastclock = ovni_ev_get_clock(stream->cur_ev); | ||||||
| 
 | 
 | ||||||
| 		/* Read the next one */ | 		/* Read the next one */ | ||||||
| 		ovni_load_next_event(stream); | 		ovni_load_next_event(stream); | ||||||
|  | |||||||
| @ -4,7 +4,7 @@ | |||||||
| #include "ovni.h" | #include "ovni.h" | ||||||
| #include "emu.h" | #include "emu.h" | ||||||
| 
 | 
 | ||||||
| void ovni_load_next_event(struct ovni_stream *stream); | int ovni_load_next_event(struct ovni_stream *stream); | ||||||
| 
 | 
 | ||||||
| int ovni_load_trace(struct ovni_trace *trace, char *tracedir); | int ovni_load_trace(struct ovni_trace *trace, char *tracedir); | ||||||
| 
 | 
 | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user