changelog shortlog tags branches changeset files file revisions raw help

Mercurial > hg > plan9front / annotate sys/src/9/port/portclock.c

changeset 6937: 62ba89f5ffb8
parent: 381f1cb08002
child: 2109eab7793b
author: cinap_lenrek@felloff.net
date: Wed, 05 Dec 2018 01:43:19 +0100
permissions: -rw-r--r--
description: kernel: fix tprof on multiprocessor

segclock() has to be called from hzclock(), otherwise
only processes running on cpu0 would catche the interrupt
and the time delta would be wrong.

lock the segment when allocating Seg->profile as
profile ctl might be issued from multiple processes.
Proc->debug qlock is not sufficient.

Seg->profile can never be freed or reallocated once
set as the timer interrupt accesses it without any
locking.
taruti@0 1
 #include "u.h"
taruti@0 2
 #include "../port/lib.h"
taruti@0 3
 #include "mem.h"
taruti@0 4
 #include "dat.h"
taruti@0 5
 #include "fns.h"
taruti@0 6
 #include "io.h"
taruti@0 7
 #include "ureg.h"
cinap_lenrek@6937 8
 #include "tos.h"
taruti@0 9
 
taruti@0 10
 struct Timers
taruti@0 11
 {
taruti@0 12
 	Lock;
taruti@0 13
 	Timer	*head;
taruti@0 14
 };
taruti@0 15
 
taruti@0 16
 static Timers timers[MAXMACH];
taruti@0 17
 
taruti@0 18
 ulong intrcount[MAXMACH];
taruti@0 19
 ulong fcallcount[MAXMACH];
taruti@0 20
 
taruti@0 21
 static vlong
taruti@0 22
 tadd(Timers *tt, Timer *nt)
taruti@0 23
 {
taruti@0 24
 	Timer *t, **last;
taruti@0 25
 
taruti@0 26
 	/* Called with tt locked */
taruti@0 27
 	assert(nt->tt == nil);
taruti@0 28
 	switch(nt->tmode){
taruti@0 29
 	default:
taruti@0 30
 		panic("timer");
taruti@0 31
 		break;
taruti@0 32
 	case Trelative:
taruti@0 33
 		if(nt->tns <= 0)
taruti@0 34
 			nt->tns = 1;
taruti@0 35
 		nt->twhen = fastticks(nil) + ns2fastticks(nt->tns);
taruti@0 36
 		break;
taruti@0 37
 	case Tperiodic:
taruti@0 38
 		assert(nt->tns >= 100000);	/* At least 100 ┬Ás period */
taruti@0 39
 		if(nt->twhen == 0){
taruti@0 40
 			/* look for another timer at same frequency for combining */
taruti@0 41
 			for(t = tt->head; t; t = t->tnext){
taruti@0 42
 				if(t->tmode == Tperiodic && t->tns == nt->tns)
taruti@0 43
 					break;
taruti@0 44
 			}
taruti@0 45
 			if (t)
taruti@0 46
 				nt->twhen = t->twhen;
taruti@0 47
 			else
taruti@0 48
 				nt->twhen = fastticks(nil);
taruti@0 49
 		}
taruti@0 50
 		nt->twhen += ns2fastticks(nt->tns);
taruti@0 51
 		break;
taruti@0 52
 	}
taruti@0 53
 
taruti@0 54
 	for(last = &tt->head; t = *last; last = &t->tnext){
taruti@0 55
 		if(t->twhen > nt->twhen)
taruti@0 56
 			break;
taruti@0 57
 	}
taruti@0 58
 	nt->tnext = *last;
taruti@0 59
 	*last = nt;
taruti@0 60
 	nt->tt = tt;
taruti@0 61
 	if(last == &tt->head)
taruti@0 62
 		return nt->twhen;
taruti@0 63
 	return 0;
taruti@0 64
 }
taruti@0 65
 
taruti@0 66
 static uvlong
taruti@0 67
 tdel(Timer *dt)
taruti@0 68
 {
taruti@0 69
 
taruti@0 70
 	Timer *t, **last;
taruti@0 71
 	Timers *tt;
taruti@0 72
 
taruti@0 73
 	tt = dt->tt;
taruti@0 74
 	if (tt == nil)
taruti@0 75
 		return 0;
taruti@0 76
 	for(last = &tt->head; t = *last; last = &t->tnext){
taruti@0 77
 		if(t == dt){
taruti@0 78
 			assert(dt->tt);
taruti@0 79
 			dt->tt = nil;
taruti@0 80
 			*last = t->tnext;
taruti@0 81
 			break;
taruti@0 82
 		}
taruti@0 83
 	}
taruti@0 84
 	if(last == &tt->head && tt->head)
taruti@0 85
 		return tt->head->twhen;
taruti@0 86
 	return 0;
taruti@0 87
 }
taruti@0 88
 
taruti@0 89
 /* add or modify a timer */
taruti@0 90
 void
taruti@0 91
 timeradd(Timer *nt)
taruti@0 92
 {
taruti@0 93
 	Timers *tt;
taruti@0 94
 	vlong when;
taruti@0 95
 
taruti@0 96
 	/* Must lock Timer struct before Timers struct */
taruti@0 97
 	ilock(nt);
taruti@0 98
 	if(tt = nt->tt){
taruti@0 99
 		ilock(tt);
taruti@0 100
 		tdel(nt);
taruti@0 101
 		iunlock(tt);
taruti@0 102
 	}
taruti@0 103
 	tt = &timers[m->machno];
taruti@0 104
 	ilock(tt);
taruti@0 105
 	when = tadd(tt, nt);
taruti@0 106
 	if(when)
taruti@0 107
 		timerset(when);
taruti@0 108
 	iunlock(tt);
taruti@0 109
 	iunlock(nt);
taruti@0 110
 }
taruti@0 111
 
taruti@0 112
 
taruti@0 113
 void
taruti@0 114
 timerdel(Timer *dt)
taruti@0 115
 {
cinap_lenrek@5848 116
 	Mach *mp;
taruti@0 117
 	Timers *tt;
taruti@0 118
 	uvlong when;
taruti@0 119
 
cinap_lenrek@5848 120
 	/* avoid Tperiodic getting re-added */
cinap_lenrek@5848 121
 	dt->tmode = Trelative;
cinap_lenrek@5848 122
 
taruti@0 123
 	ilock(dt);
taruti@0 124
 	if(tt = dt->tt){
taruti@0 125
 		ilock(tt);
taruti@0 126
 		when = tdel(dt);
taruti@0 127
 		if(when && tt == &timers[m->machno])
taruti@0 128
 			timerset(tt->head->twhen);
taruti@0 129
 		iunlock(tt);
taruti@0 130
 	}
cinap_lenrek@5848 131
 	if((mp = dt->tactive) == nil || mp->machno == m->machno){
cinap_lenrek@5848 132
 		iunlock(dt);
cinap_lenrek@5848 133
 		return;
cinap_lenrek@5848 134
 	}
taruti@0 135
 	iunlock(dt);
cinap_lenrek@5848 136
 
cinap_lenrek@5848 137
 	/* rare, but tf can still be active on another cpu */
cinap_lenrek@5848 138
 	while(dt->tactive == mp && dt->tt == nil)
cinap_lenrek@5848 139
 		if(up->nlocks == 0 && islo())
cinap_lenrek@5848 140
 			sched();
taruti@0 141
 }
taruti@0 142
 
taruti@0 143
 void
taruti@0 144
 hzclock(Ureg *ur)
taruti@0 145
 {
taruti@0 146
 	m->ticks++;
taruti@0 147
 	if(m->proc)
taruti@0 148
 		m->proc->pc = ur->pc;
taruti@0 149
 
taruti@0 150
 	if(m->flushmmu){
taruti@0 151
 		if(up)
taruti@0 152
 			flushmmu();
taruti@0 153
 		m->flushmmu = 0;
taruti@0 154
 	}
taruti@0 155
 
taruti@0 156
 	accounttime();
taruti@0 157
 	kmapinval();
taruti@0 158
 
taruti@0 159
 	if(kproftimer != nil)
taruti@0 160
 		kproftimer(ur->pc);
taruti@0 161
 
cinap_lenrek@5034 162
 	if(active.machs[m->machno] == 0)
taruti@0 163
 		return;
taruti@0 164
 
cinap_lenrek@3465 165
 	if(active.exiting)
taruti@0 166
 		exit(0);
taruti@0 167
 
cinap_lenrek@2727 168
 	if(m->machno == 0)
cinap_lenrek@2727 169
 		checkalarms();
taruti@0 170
 
cinap_lenrek@6937 171
 	if(up && up->state == Running){
cinap_lenrek@6937 172
 		if(userureg(ur)){
cinap_lenrek@6937 173
 			/* user profiling clock */
cinap_lenrek@6937 174
 			Tos *tos = (Tos*)(USTKTOP-sizeof(Tos));
cinap_lenrek@6937 175
 			tos->clock += TK2MS(1);
cinap_lenrek@6937 176
 			segclock(ur->pc);
cinap_lenrek@6937 177
 		}
cinap_lenrek@6937 178
 
taruti@0 179
 		hzsched();	/* in proc.c */
cinap_lenrek@6937 180
 	}
taruti@0 181
 }
taruti@0 182
 
taruti@0 183
 void
taruti@0 184
 timerintr(Ureg *u, Tval)
taruti@0 185
 {
taruti@0 186
 	Timer *t;
taruti@0 187
 	Timers *tt;
taruti@0 188
 	uvlong when, now;
taruti@0 189
 	int callhzclock;
taruti@0 190
 	static int sofar;
taruti@0 191
 
taruti@0 192
 	intrcount[m->machno]++;
taruti@0 193
 	callhzclock = 0;
taruti@0 194
 	tt = &timers[m->machno];
taruti@0 195
 	now = fastticks(nil);
taruti@0 196
 	ilock(tt);
taruti@0 197
 	while(t = tt->head){
taruti@0 198
 		/*
taruti@0 199
 		 * No need to ilock t here: any manipulation of t
taruti@0 200
 		 * requires tdel(t) and this must be done with a
taruti@0 201
 		 * lock to tt held.  We have tt, so the tdel will
taruti@0 202
 		 * wait until we're done
taruti@0 203
 		 */
taruti@0 204
 		when = t->twhen;
taruti@0 205
 		if(when > now){
taruti@0 206
 			timerset(when);
taruti@0 207
 			iunlock(tt);
taruti@0 208
 			if(callhzclock)
taruti@0 209
 				hzclock(u);
taruti@0 210
 			return;
taruti@0 211
 		}
taruti@0 212
 		tt->head = t->tnext;
taruti@0 213
 		assert(t->tt == tt);
taruti@0 214
 		t->tt = nil;
cinap_lenrek@5848 215
 		t->tactive = MACHP(m->machno);
taruti@0 216
 		fcallcount[m->machno]++;
taruti@0 217
 		iunlock(tt);
taruti@0 218
 		if(t->tf)
taruti@0 219
 			(*t->tf)(u, t);
taruti@0 220
 		else
taruti@0 221
 			callhzclock++;
cinap_lenrek@5848 222
 		t->tactive = nil;
taruti@0 223
 		ilock(tt);
taruti@0 224
 		if(t->tmode == Tperiodic)
taruti@0 225
 			tadd(tt, t);
taruti@0 226
 	}
taruti@0 227
 	iunlock(tt);
taruti@0 228
 }
taruti@0 229
 
taruti@0 230
 void
taruti@0 231
 timersinit(void)
taruti@0 232
 {
taruti@0 233
 	Timer *t;
taruti@0 234
 
taruti@0 235
 	/*
taruti@0 236
 	 * T->tf == nil means the HZ clock for this processor.
taruti@0 237
 	 */
taruti@0 238
 	todinit();
taruti@0 239
 	t = malloc(sizeof(*t));
cinap_lenrek@1244 240
 	if(t == nil)
cinap_lenrek@1244 241
 		panic("timersinit: no memory for Timer");
taruti@0 242
 	t->tmode = Tperiodic;
taruti@0 243
 	t->tt = nil;
taruti@0 244
 	t->tns = 1000000000/HZ;
taruti@0 245
 	t->tf = nil;
taruti@0 246
 	timeradd(t);
taruti@0 247
 }
taruti@0 248
 
taruti@0 249
 Timer*
taruti@0 250
 addclock0link(void (*f)(void), int ms)
taruti@0 251
 {
taruti@0 252
 	Timer *nt;
taruti@0 253
 	uvlong when;
taruti@0 254
 
taruti@0 255
 	/* Synchronize to hztimer if ms is 0 */
taruti@0 256
 	nt = malloc(sizeof(Timer));
cinap_lenrek@1244 257
 	if(nt == nil)
cinap_lenrek@1244 258
 		panic("addclock0link: no memory for Timer");
taruti@0 259
 	if(ms == 0)
taruti@0 260
 		ms = 1000/HZ;
taruti@0 261
 	nt->tns = (vlong)ms*1000000LL;
taruti@0 262
 	nt->tmode = Tperiodic;
taruti@0 263
 	nt->tt = nil;
taruti@0 264
 	nt->tf = (void (*)(Ureg*, Timer*))f;
taruti@0 265
 
taruti@0 266
 	ilock(&timers[0]);
taruti@0 267
 	when = tadd(&timers[0], nt);
taruti@0 268
 	if(when)
taruti@0 269
 		timerset(when);
taruti@0 270
 	iunlock(&timers[0]);
taruti@0 271
 	return nt;
taruti@0 272
 }
taruti@0 273
 
taruti@0 274
 /*
taruti@0 275
  *  This tk2ms avoids overflows that the macro version is prone to.
taruti@0 276
  *  It is a LOT slower so shouldn't be used if you're just converting
taruti@0 277
  *  a delta.
taruti@0 278
  */
taruti@0 279
 ulong
taruti@0 280
 tk2ms(ulong ticks)
taruti@0 281
 {
taruti@0 282
 	uvlong t, hz;
taruti@0 283
 
taruti@0 284
 	t = ticks;
taruti@0 285
 	hz = HZ;
taruti@0 286
 	t *= 1000L;
taruti@0 287
 	t = t/hz;
taruti@0 288
 	ticks = t;
taruti@0 289
 	return ticks;
taruti@0 290
 }
taruti@0 291
 
taruti@0 292
 ulong
taruti@0 293
 ms2tk(ulong ms)
taruti@0 294
 {
taruti@0 295
 	/* avoid overflows at the cost of precision */
taruti@0 296
 	if(ms >= 1000000000/HZ)
taruti@0 297
 		return (ms/1000)*HZ;
taruti@0 298
 	return (ms*HZ+500)/1000;
taruti@0 299
 }