-
Notifications
You must be signed in to change notification settings - Fork 1
/
a10c_20.txt
549 lines (507 loc) · 25.9 KB
/
a10c_20.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
==== 20주차(2013.09.07) ====
<box center round blue 95% | <typo fs:18px;> ** 1. printk_ratelimit() -> raw_spin_trylock_irqsaves() ** </typo>>
\\
{{:스터디:raw_spin_trylock_irqsaves3.png?direct |}}
\\
\\
<WRAP center round box 95%>
<typo fs:16px;>
** 1) 왜 함수의 네이밍을 hardirq라고 했을까요? hard의 의미가 있을까요? ** </typo>
<code c>
#define local_irq_save(flags) \
do { \
raw_local_irq_save(flags); \
trace_hardirqs_off(); \
} while (0)
</code>
----
> hard의 의미는 processor상의 irq를 on/off라고 지칭하는 것입니다.
> soft는 변수를 가지고 제어하는 것입니다.
</WRAP>
<WRAP center round box 95%>
<typo fs:16px;>
** 2) _lockfunc은 무엇일까요? ** </typo>
<code c>
int _lockfunc _raw_spin_trylock(raw_spinlock_t *lock)
{
return __raw_spin_trylock(lock);
}
</code>
----
> attribute이고, 열어보시면 다음과 같이 정의되어 있습니다. spinlock section 이라고 보시면 됩니다.
> <code>
#define __lockfunc __attribute__((section(".spinlock.text")))
</code>
> 하지만 18주차때 elf보시면 그런 section은 없습니다.
> <code>
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .head.text PROGBITS c0008000 008000 0001c0 00 AX 0 0 4
[ 2] .text PROGBITS c00081c0 0081c0 35c32c 00 AX 0 0 64
[ 3] .rodata PROGBITS c0365000 365000 0e2ef0 00 A 0 0 64
[ 4] __bug_table PROGBITS c0447ef0 447ef0 005b20 00 A 0 0 1
[ 5] __ksymtab PROGBITS c044da10 44da10 0060b0 00 A 0 0 4
[ 6] __ksymtab_gpl PROGBITS c0453ac0 453ac0 003640 00 A 0 0 4
[ 7] __ksymtab_strings PROGBITS c0457100 457100 01522c 00 A 0 0 1
[ 8] __param PROGBITS c046c32c 46c32c 000750 00 A 0 0 4
[ 9] __modver PROGBITS c046ca7c 46ca7c 000584 00 A 0 0 4
[10] __ex_table PROGBITS c046d000 46d000 000fc8 00 A 0 0 8
[11] .ARM.unwind_idx ARM_EXIDX c046dfc8 46dfc8 019e20 00 AL 16 0 4
[12] .ARM.unwind_tab PROGBITS c0487de8 487de8 0024a8 00 A 0 0 4
[13] .notes NOTE c048a290 48a290 000024 00 AX 0 0 4
[14] .vectors PROGBITS 00000000 490000 000020 00 AX 0 0 4
[15] .stubs PROGBITS 00001000 491000 000240 00 AX 0 0 32
[16] .init.text PROGBITS c048b260 493260 01d4fc 00 AX 0 0 32
[17] .exit.text PROGBITS c04a875c 4b075c 000c30 00 AX 0 0 4
[18] .init.arch.info PROGBITS c04a938c 4b138c 000054 00 A 0 0 4
[19] .init.tagtable PROGBITS c04a93e0 4b13e0 000048 00 A 0 0 4
[20] .init.smpalt PROGBITS c04a9428 4b1428 0001f0 00 A 0 0 4
[21] .init.pv_table PROGBITS c04a9618 4b1618 0002f4 00 A 0 0 1
[22] .init.data PROGBITS c04a9910 4b1910 00ba4c 00 WA 0 0 8
[23] .data..percpu PROGBITS c04b6000 4be000 001d00 00 WA 0 0 64
[24] .data PROGBITS c04b8000 4c0000 035100 00 WA 0 0 64
[25] .bss NOBITS c04ed100 4f5100 041ae0 00 WA 0 0 64
</code>
> 이 현상은 vmlinux.lds파일을 확인해 보시면, .text section에 spinlock.text가 포함된 것을 볼 수 있습니다.
> <code c>
.text : { /* Real text segment */
_stext = .; /* Text and read-only data */
__exception_text_start = .;
*(.exception.text)
__exception_text_end = .;
. = ALIGN(8); *(.text.hot) *(.text) *(.ref.text) *(.devinit.text) *(.devexit.text) *(.cpuinit.text) *(.cpuexit.text) *(.text.unlikely)
. = ALIGN(8); __sched_text_start = .; *(.sched.text) __sched_text_end = .;
. = ALIGN(8); __lock_text_start = .; *(.spinlock.text) __lock_text_end = .;
. = ALIGN(8); __kprobes_text_start = .; *(.kprobes.text) __kprobes_text_end = .;
. = ALIGN(8); __idmap_text_start = .; *(.idmap.text) __idmap_text_end = .; . = ALIGN(32); __hyp_idmap_text_start = .; *(.hyp.idmap.text) __hyp_idmap_text_end = .;
</code>
</WRAP>
<WRAP center round box 95%>
<code c>
void __kprobes add_preempt_count(int val)
{
#ifdef CONFIG_DEBUG_PREEMPT // ARM10C Y
/*
* Underflow?
*/
// ARM10C 20130907 preempt_count()가 0 보다 작은 경우는 bug이다.
if (DEBUG_LOCKS_WARN_ON((preempt_count() < 0)))
return;
#endif
preempt_count() += val;
// ARM10C 20130907 0x40000001 + 1(val)
#ifdef CONFIG_DEBUG_PREEMPT
/*
* Spinlock count overflowing soon?
*/
DEBUG_LOCKS_WARN_ON((preempt_count() & PREEMPT_MASK) >=
PREEMPT_MASK - 10);
#endif
// ARM10C 20130907 preempt_count = 0x40000002
if (preempt_count() == val)
trace_preempt_off(CALLER_ADDR0, get_parent_ip(CALLER_ADDR1));
}
</code>
<typo fs:16px;>
** 3) _kprobes가 나오는데 무엇일까요? ** </typo>
----
> 커널 코드에 원하는 작업을 동적으로 추가할 수 있는 강력한 디버깅 기법이다.
> Ref. [[http://www.chunghwan.com/ko/systems/how-kprobes-works-1/ | Kprobes 동작 방식 #1]]
</WRAP>
<WRAP center round box 95%>
<typo fs:16px;>
** 4) 위 code처럼 계속 preempt count를 통하여 preemption을 막는다고 하는데 어떻게 할까요? ** </typo>
----
> Interrupt Handler에서 count를 이용하여 0이상이면 preempt가 발생하지 못하게 할것이다.
> 조금 더 자세한 내용은 스케쥴러에 들어가면 확인해 보자.
</WRAP>
<WRAP center round box 95%>
<typo fs:16px;>
** 5) 그럼 숫자를 조금만 추가하면 될것인데, 왜 0x4000_0001가 들어갔을까요? ** </typo>
----
> 지난시간에도 토론했듯이, 지금은 충분한 숫자를 미리 넣어두었을 뿐이다.
> 향후에 start_kernel()->sched_init()->init_idle() 의 함수에 의해 다시 재조정 될 것이다.
</WRAP>
<WRAP center round box 95%>
<typo fs:16px;>
** 6) 위 code에서 preempt_count()+=val이 가능한 문법인가? 함수에 어떻게 값을 더할 수 있나요? ** </typo>
----
> 따라가보면 preempt_count()는 함수가 아니라 구조체 값입니다.
> 그래서 가능합니다.
</WRAP>
<WRAP center round box 95%>
<typo fs:16px;>
** 7) 그래도 혼란스럽다. 지금은 scheduler가 off상태인데, preempt 자체가 필요가 있을까? ** </typo>
----
> 말씀하신것처럼, 현재는 의미가 없을수도 있습니다. 하지만 이 함수는 나중에 계속 사용하는 함수입니다.
</WRAP>
<WRAP center round box 95%>
원래는 arch_spin_trylock 코드를 봐야 하지만, 이해를 돕기 위해 arch_spin_lock 코드를 봤습니다.
<code c>
static inline void arch_spin_lock(arch_spinlock_t *lock)
{
unsigned long tmp;
u32 newval;//다음 next 값
arch_spinlock_t lockval;//현재 next 값
//ARM10C 20130907
//"1: ldrex lockval, &lock->slock\n"
//현재 next(lockval)는 받아 놓고,
//" add newval, lockval, (1<<TICKET_SHIFT)\n" tickets.next += 1
//다음 next(newval) 는 += 1하고 저장 한다.
//" strex tmp, newval, &lock->slock\n"
//" teq tmp, #0\n"
//" bne 1b"
// lock->slock에서 실제 데이터를 쓸때(next+=1) 까지 루프
// next+=1 의 의미는 표를 받기위해 번호표발행
__asm__ __volatile__(
"1: ldrex %0, [%3]\n"
" add %1, %0, %4\n"
" strex %2, %1, [%3]\n"
" teq %2, #0\n"
" bne 1b"
: "=&r" (lockval), "=&r" (newval), "=&r" (tmp)
: "r" (&lock->slock), "I" (1 << TICKET_SHIFT)
: "cc");
// 실재 lock을 걸기 위해 busylock 한다.
// 받은 번호표의 순을 기다린다.(unlock에서 owner을 증가 시켜서)
while (lockval.tickets.next != lockval.tickets.owner) {
wfe(); // ARM10C 이벤트대기(irq,frq,부정확한 중단 또는 디버그 시작 요청 대기. 구현되지 않은 경우 NOP
// arch_spin_unlock()의 dsb_sev();가 호출될때 깨어남
lockval.tickets.owner = ACCESS_ONCE(lock->tickets.owner);
// ARM10C local owner값 업데이트
}
smp_mb();
}
</code>
<typo fs:16px;>
** 8) LDREX, STREX에 대해서 다시 정리해보자. ** </typo>
----
> STREX는 swap결과에 따라 성공하면 tmp에 0을넣고, 실패하면 1을 넣는 구문입니다.
>
> 이 명령어들 자체가 예전 아키텍처에서 swp명령이 cost가(속도가 느림) 많이 발생하기 때문에, 나오게된 명령들입니다.
> 해당 명령어가 추가되었다는 의미는, AMBA 버스에 원래 기존 load signal이 존재하였는데,
> 속도문제로 transaction이 따로 추가되어 이 명령어들은 독립적으로 signal이 나옵니다.
>
> 그리고 혼란스러워 하시는것 같은데, spinlock은 atomic lock을 하기위한 수단일 뿐입니다.
>>
>> [[http://www.iamroot.org/xe/index.php?_filter=search&mid=Kernel_8_ARM&search_keyword=STREX&search_target=title_content&document_srl=66152 | 8차 스터디 글]]
>> <wrap em>위의 글은 LDREX/STREX의 동작에 대한 설명이 아니다.</wrap>
>> 해당 글은 <wrap em>local monitor와 관련하여 context switching시 CLREX를 하는 이유</wrap>에 대한 설명이다.
>>
>> 상위 관점에서 STREX와 LDREX를 설명하면 아래와 같다.
>> 일단 비교대상인 SWP는 당연히 Rn 주소에서 값을 읽어오고(Rt) 전달된 값(Rt2)을 write
>> LDREX는 항상 동작하며 Rn주소에서 읽은 값을 Rt에 저장함과 동시에 메모리 상태를 exclusive access상태로 변경
>> STREX는 메모리 상태에 따라 STR 실행 여부를 결정. (실행 여부는 Rd(위의 tmp변수)값으로 확인)
>>
>> ※ STREX 실행 여부를 결정하는 메모리 상태는 CLREX 실행 여부, 다른 agent에 의한 STREX/STR 실행 여부 등에 의해 변경.
>>
>>
>> <fc #0000FF>- 주의 -</fc>
>> LDREX/STREX는 HW 제약으로 정확하게 동일 어드레스가 아닌 비슷한 range에 들어도 동작하므로 SW작성에 주의가 필요.
>> 또한 1코어내의 서로 다른 thread에서 수행하는 LDREX, STREX를 구분할수 없으므로 (정확하게는 **IMPLEMENTATION DEFINED**)
>> ※ 8차 스터디 글에서 나타낸 바와 같이 context switching시에 dummy STREX 또는 CLREX의 수행이 필요.
>>
>>
>> HW적인 관점에서 STREX와 LDREX를 설명하면 아래와 같다. (SWP vs. STREX/LDREX)
>> **1)** 먼저 <wrap em>SWP</wrap>은 bus가 lock된 (bus arbiter가 다른 master들이 해당 slave로 접근하지 못하도록 제어) 상태에서 ldr&str가 순차적으로 수행되는 단순한 구조
>>
>> {{ :스터디:swp.png?direct&600 |}}
>>
>> **2)** <wrap em>LDREX와 STREX</wrap>의 경우 최근에 access한 agent, 값 등에 대한 정보를 local monitor와 global monitor에 저장하고, STREX의 수행여부를 결정
>> {{ :스터디:strex.png?direct&600 | }}
>>
>> 따라서 LDREX, STREX의 경우 Core 또는 memory IF에 monitor를 구현하기 위한 tag memory와 FSM이 필요하다.
>> monitor관련 자세한 내용은 AARM v7의 A3.4절 참조, Figure A3-3,4에 local, global monitor의 state machine이 나타나 있다.
>>
>>>
>>> <wrap em>SWP를 Exclusive access(LDREX, STREX)로 대체한 이유에 대한 ARM사의 설명</wrap>입니다.
>>> Ref.: [[http://infocenter.arm.com/help/topic/com.arm.doc.dht0008a/DHT0008A_arm_synchronization_primitives.pdf | ARM
Synchronization Primitives]], A1.2 Limitations of SWP and SWPB
>>>
>>> 요약하면,
>>> **1.** SWP의 (LOAD+STORE)를 LDREX, STREX로 분리하여 <wrap em>Pipeline stall 및 interrupt latency 향상</wrap>
>>>
>>> **2.** Multicore등의 환경에서 <wrap em>memory lock으로 인한 메모리 성능 저하 방지</wrap>
>>> (bus상에서 하나의 master가 lock하고 있는 slave에 다른 master는 lock해제시까지 대기해야함)
>>>
>>> **3.** SWP은 LOCK만 구현가능하지만(swap만으로는 increment/decrement가 불가), LDREX,STREX는 세마포어 구현이 가능하다.(물론 lock이 구현된다면 lock으로 semaphore구현은 가능, 다만 여기서는 직접 구현 가능 여부를 말함)
>>>
>>> ※ SWP은 AXI4(ACE) 이후부터 지원되지 않음(관련 시그널이 삭제되었음)
>>>
>>> 관련한 학술적 내용은 Computer Architecture 교재나 강의 자료의 synchronization을 읽어보시는 것도 좋습니다.
>>> fetch and add/compare and swap(CAS)/load linked & store conditional(LLSC)로 분류하여 설명한 자료들이 있네요.
>>> 물론 WIKI에도 있을 거에요.
>>>
>>> <fc #0000FF>질문 사항은 iamroot 게시판 또는 스터디 시간을 활용해주세요.</fc>
</WRAP>
<WRAP center round box 95%>
<typo fs:16px;>
** 9) SPINLOCK에 대해서 다시한번 짚고 넘어가야 할 것 같습니다. ** </typo>
----
> spin lock은 mutiprocessor system에서 여러 processor가 동시에 critical section에 진입하지 못하도록 하는 synchronization 기법이다. 한 processor가 lock을 가지고 있으면 다른 processor들은 unlock될 때까지 busy-wait하다가 lock을 차지하기 위해 동시에 lock 변수에 접근(write)한다.
>
> 기존의 spin lock은 2가지 문제점이 존재하였습니다.
> <wrap em>1) 각 processor간에 lock을 획득하는 순서 보장 못함</wrap>
> <wrap em>2) 한 processor가 lock 변수에 write를 하면 다른 processor의 cache line이 invalidate되어 성능이 악화</wrap>
>
> 이를 해결하기 위해서 2.6.25버전부터 ticker spin lock이 도입되어, 각 processor들은 자신만의 ticket을 부여받고
> 자기 차례가 돌아오는 경우에만 write를 시도하여, 순서대로 lock을 얻고 전체적으로 cache miss 횟수를 줄입니다.
> (Ref. [[http://studyfoss.egloos.com/5144295 | [Linux] ticket spin lock]])
>
> 라고는 하지만, 역시 이해하기에는 그림이 짱짱이죠? ticket spin lock은 은행 or 영화관의 티켓 발권기로 보시면 됩니다.
> {{:스터디:tickers_owner2.png?direct |}}
>
> 위와같이 티켓을 뽑았습니다. 번호는 79번이네요. 앞에 8명이나 있으니 계속 대기해야 합니다.
> {{:스터디:tickets_next.png?direct |}}
>
> 당연히 창구를 이용하고 있다면, 다른 사람은 대기 해야 겠죠? 그러다가 창구번호(tickets.owner)가 자신의 번호표(tickets.next)와 같아지면, 그때 이용 가능합니다.
</WRAP>
<WRAP center round box 95%>
<typo fs:16px;>
** 10) 그런데 이런경우 spin lock의 단점이 보입니다. 자료형이 U16으로 선언되어 있는데, 이 숫자를 넘어가면 overflow가 일어날 수 있겠네요. ** </typo>
----
> 프로세서의 개수라서 16비트면 2^16개 입니다. 임베디드에서 그럴 확률은 아직 머나먼 미래의 얘기일 것 같습니다.
</WRAP>
<WRAP center round box 95%>
<typo fs:16px;>
** 11) 위 code에서 wfe()는 무슨 기능을 하나요? ** </typo>
----
> event가(irq, fiq등) 들어오기 전까지 sleep이라고 보시면 됩니다. 보통은 interrupt가 들어와야 깨어 납니다.
> 여기서는 다른 프로세서가 시그널을 보낼것 입니다.
</WRAP>
<WRAP center round box 95%>
<typo fs:16px;>
** 12) subs %1, %0, %0, ror #16\n"에서 ror연산의 의미가 무엇일까요? ** </typo>
<code c>
static inline int arch_spin_trylock(arch_spinlock_t *lock)
{
unsigned long tmp;
u32 slock;
__asm__ __volatile__(
" ldrex %0, [%2]\n"
" subs %1, %0, %0, ror #16\n"
" addeq %0, %0, %3\n"
" strexeq %1, %0, [%2]"
: "=&r" (slock), "=&r" (tmp)
: "r" (&lock->slock), "I" (1 << TICKET_SHIFT)
: "cc");
...
</code>
}
----
> ror연산은 shift연산과 비슷하지만, 오른쪽으로 회전하라는 의미입니다.
> {{:스터디:ror.png?direct |}}
> 따라서, 위 구문은 next와 owner의 값이 같은지 체크하는 구문입니다.
</WRAP>
<WRAP center round box 95%>
<typo fs:16px;>
** 13) 위에서 우리는 lock과 try-lock 함수를 보았는데, 무엇이 틀린가요? ** </typo>
----
> lock을 획득할 때까지 기다리는 것입니다. (block)
> try-lock은 시도하다가 안되면 그냥 넘어가는 lock입니다. (non-block)
</WRAP>
<WRAP center round box 95%>
<typo fs:16px;>
** 14) 아래 code를 보면 lock 전후로 dmb, dsb명령을 수행합니다. 왜 이렇게 사용할까요? ** </typo>
<code c>
static inline void arch_spin_unlock(arch_spinlock_t *lock)
{
smp_mb();
lock->tickets.owner++;
dsb_sev(); // ARM10C 이벤트발생
}
</code>
----
> 앞의 dmb 명령은 미리 정리를 해서 안섞이게 할려고 하는 것이다.
> 중요한 키가 존재하고, 내가 작업을 하고 있는데 owner를 미리 바꾸면 값이 이상해 진다.
>
> owner를 추가하고 dsb 명령을 수행하는 이유는 memory까지 확실히 전달되어야,
> 다음에 다른 프로세서가 깨어나서 공유자원을 보더라도 확실할 것이다.
> 결국 owner값을 보호하기 위해서 하는 것이다.
</WRAP>
<WRAP center round box 95%>
<typo fs:16px;>
** 15) _CHECKER_가 의미하는 바가 무엇일까요? ** </typo>
<code c>
#ifdef __CHECKER__
# define __user __attribute__((noderef, address_space(1)))
# define __kernel __attribute__((address_space(0)))
# define __safe __attribute__((safe))
...
# define __cond_lock(x,c) ((c) ? ({ __acquire(x); 1; }) : 0)
#else
# define __user
# define __kernel
# define __safe
...
# define __cond_lock(x,c) (c) //ARM10C this
#endif
</code>
----
> [[wp>Sparse]]에 관한 설정으로 리눅스용 코드 정적 분석 툴입니다.
>
> Sparse is a <wrap em>computer software tool designed to find possible coding faults</wrap> in the Linux kernel
>
> 상세 정보는 /documentation/sparse.txt에 정의되어 있습니다.
</WRAP>
</box>
\\
<box center round blue 95% | <typo fs:18px;> ** 2. printk_ratelimit() -> time_is_before_jiffies() ** </typo>>
\\
<WRAP center round box 95%>
<typo fs:16px;>
** 1) jiffies가 무엇인가요? ** </typo>
----
> time tick이 발생할때 마다 추가되는 변수입니다. type은 long입니다.
</WRAP>
<WRAP center round box 95%>
<typo fs:16px;>
** 2) 요즘 시스템은 time tick이 얼마나 되나요? ** </typo>
----
> 예전에는 100이었는데 요즘은 1000입니다. 즉, 1ms입니다.
> ms는 이걸로 측정하고, ns는 busy wait 해버립니다.
> 실제로 개발하면 sleep을 많이 사용하는데, 시간이 정확하지는 않습니다.
>
> <del> 스케쥴러에게 받아야 의미가 있다?? 여기서는 의미가 없다?? 이 말뜻을 잘 이해못했네요. 부연설명 부탁 드립니다. </del>
> time tick과 jiffies은 timer isr에 의해 update된다. 현재 IRQ가 disabled상태이므로 의미가 없다는 이야기.
> scheduler 얘기가 나온것은 보통 timer isr에 의해 수행되는 것이 scheduler이기 때문에 나중에 scheduler가 enabled되는 시점에 time tick 등이 update되어 해당 ratelimit함수가 유효해지기 때문에 등장한 내용.
</WRAP>
<WRAP center round box 95%>
<typo fs:16px;>
** 3) typecheck()를 실제로도 사용하나요? ** </typo>
<code c>
#define time_after(a,b) \
(typecheck(unsigned long, a) && \
typecheck(unsigned long, b) && \
((long)(b) - (long)(a) < 0))
</code>
----
> 실제로 본적은 없습니다. 다만 개발할때 보통 지역변수로 flag를 기입하니까 그 error를 체크하지 않을까 합니다.
>
> 오늘 Computer Architecture 강의를 들으러 가서 이것저것 여쭤봤는데, 교수님께서 이런 얘기를 해주시네요.
> 그냥 참고하시기 바랍니다.
>
> Hardware적으로 type을 체크할 수는 없다. (Commercial 기준, research용 hardware는 tag를 따로 기입한다고 합니다.)
> 따라서, 현재로서는 software로 type을 체크할 수 밖에 없다.
</WRAP>
</box>
\\
<box center round blue 95% | <typo fs:18px;> ** 3. boot_cpu_init() -> set_cpu_online(), set_cpu_active(), set_cpu_present(), set_cpu_possible() ** </typo>>
\\
{{:스터디:set_cpu_online.png?direct |}}
\\
\\
<WRAP center round box 95%>
<typo fs:16px;>
** 1) 기존 this_cpu값 다시 논의함 ** </typo>
----
<del>> 원래 멀티코어 프로세서가 부팅하면, bootloader가 1개의 CPU만을 남겨두고 나머지는 전부 재웁니다.
> 따라서 bootloader가 하기 나름입니다.
>
> 그래도 일단, software상의 초기값으로는 0이 맞다. 이 부분은 실제 타겟을 통한 검증이 필요할것 같다.</del>
> this_cpu는 threadinfo에 저장된 cpuid로 logical id로 physical core id는 0이 아닐 수 있다.
> boot rom 등에서 MPCore중 1개의 core만 enable하고 수행하는데 이때의 core id는 선택가능하다.(physical id는 any)
> linux kernel은 초기화를 수행한 boot core를 logical ID 0로 정한다.
>> smp_setup_processor_id()에서 현재 수행하는 core id를 검사(MPIDR)하여 logical id 0에 mapping 한다.
> 현재 threadinfo에 저장된 값은 logical ID로 0이다.
> physical id가 필요한 경우 다음과 같은 코드가 사용된다.
<code c>
cpu_logical_map(smp_processor_id())
</code>
>
> 추가적으로 확인이 필요한 부분은 일부만 초기화하는 global variable의 data를 compiler가<fc #FF0000>** 항상**</fc> 나머지는 0으로 초기화하는 가이다.
> 일단 gcc에서는 일부만 초기화하는 전역 변수라도 elf상에는 전체 size가 .data 섹션에 만들어지며 초기화된 값 이외에도 0으로 저장되고 있다.
</WRAP>
<WRAP center round box 95%>
<typo fs:16px;>
** 2) 어셈블리로 set_bit를 하는 이유가 무엇일까요? 해당기능은 C언어 함수로도 존재합니다. ** </typo>
<code asm>
.macro bitop, name, instr
ENTRY( \name )
UNWIND( .fnstart )
ands ip, r1, #3
strneb r1, [ip] @ assert word-aligned
mov r2, #1
and r3, r0, #31 @ Get bit offset
mov r0, r0, lsr #5
add r1, r1, r0, lsl #2 @ Get word offset
mov r3, r2, lsl r3
1: ldrex r2, [r1]
\instr r2, r2, r3
strex r0, r2, [r1]
cmp r0, #0
bne 1b
bx lr
UNWIND( .fnend )
ENDPROC(\name )
.endm
</code>
----
> 함수명 그대로 atomic하게 실행하려고 하는 것이 그 이유입니다.
</WRAP>
<WRAP center round box 95%>
<typo fs:16px;>
** 3) 스터디 내용과는 조금 무관하지만, 전에 mov를 사용할때 상수값은 8비트만 사용하고, 로테이션 하고 그랬는데, 실제 필드에서도 그렇게 사용하나요? ** </typo>
----
> 대부분의 경우 pseudo instruction을 사용한다.(예: LDR rn, =0xXXXXXXXX)
> 컴파일러가 알아서 MOV로 풀지 ldr로 가져올지 결정한다.
> 대부분의 상황에서 cache가 hit되므로 LDR등이 1cycle로 수행가능하다.
> cache disabled이고 loop안에서 반복 사용되고 bottleneck이라 성능 최적화가 필요한 경우에나 고민하여 작성한다.
</WRAP>
<WRAP center round box 95%>
<typo fs:16px;>
** 4) 나머지 set_cpu_active(), set_cpu_present(), set_cpu_possible()는 전부 동작이 같습니다. 역할만 정의하고 갑시다. ** </typo>
----
> 시스템 상에 존재하는 CPU의 상태 정보는 다음과 같은 4개의 비트맵 (cpumask_t)으로 관리한다.
>
> **cpu_possible_mask** - 해당 비트에 대한 CPU가 존재할 수 있다.
> : 시스템에서 현재 핫플러그(hot plug)가 가능한 CPU들에 대한 비트맵이다. 해당 맵은 부팅시 시스템이 지원할 CPU의 수에 대한 것으로 비트가 설정되면 추가되거나 제거될 수 없다.
>
> **cpu_present_mask** - 해당 비트에 대한 CPU가 존재한다.
> : 시스템에 존재하는 CPU를 나타내는 비트맵이지만, CPU들이 모두 온라인상태는 아니다. 예를들어, ACPI와 같은 서브시스템에 의해 물리적으로 핫플러그가 처리될 때 해당 비트가 설정된다.
>
> **cpu_online_mask** - 해당 비트에 대한 CPU가 존재하며 스케줄러가 이를 관리한다.
> : 온라인(사용중인) 되어있는 모든 CPU에 대한 비트들을 1로 설정한 비트맵이다. 커널 스케쥴링이나 디바이스로부터 인터럽트를 받을 준비가 되어있다면 해당 비트가 설정된다. 인터럽트를 포함한 모든 OS 서비스가 다른 CPU로 이동되면 해당 비트는 지워진다.
>
> **cpu_active_mask** - 해당 비트에 대한 CPU가 존재하며 task migration 시 이를 이용할 수 있다.
>
>
> Ref. [[http://cafe.daum.net/lksas/8HoZ/42?docid=1K80b8HoZ4220110218025952 | 예전에 cpu possible, online, present, active 정리됐었나요?]]
> Ref. 모기향책 p.144
>
> 리눅스 콘솔에서 cpu에 대한 possible, online, present의 정보는
> /sys/devices/system/cpu 정보에 파일을 참조하여 알 수 있다.
>
> <code>
drwxr-xr-x 9 root root 0 2013-09-12 15:39 ./
drwxr-xr-x 12 root root 0 2013-09-12 15:39 ../
drwxr-xr-x 7 root root 0 2013-09-12 15:53 cpu0/
drwxr-xr-x 7 root root 0 2013-09-12 15:53 cpu1/
drwxr-xr-x 7 root root 0 2013-09-12 15:53 cpu2/
drwxr-xr-x 7 root root 0 2013-09-12 15:53 cpu3/
drwxr-xr-x 3 root root 0 2013-09-12 15:53 cpufreq/
drwxr-xr-x 2 root root 0 2013-09-12 15:53 cpuidle/
-r--r--r-- 1 root root 4096 2013-09-12 15:53 kernel_max
-r--r--r-- 1 root root 4096 2013-09-12 15:53 offline
-r--r--r-- 1 root root 4096 2013-09-12 15:53 online
drwxr-xr-x 2 root root 0 2013-09-12 15:53 perf_events/
-r--r--r-- 1 root root 4096 2013-09-12 15:53 possible
-r--r--r-- 1 root root 4096 2013-09-12 15:53 present
-rw-r--r-- 1 root root 4096 2013-08-19 11:37 sched_mc_power_savings
jin@jin-desktop:/sys/devices/system/cpu$ cat possible
0-7
jin@jin-desktop:/sys/devices/system/cpu$ cat present
0-3
jin@jin-desktop:/sys/devices/system/cpu$ cat online
0-3
jin@jin-desktop:/sys/devices/system/cpu$ cat offline
4-7,8-15
</code>
</WRAP>
</box>
\\
\\
\\