본문 바로가기

Linux Kernel

[Linux Kernel] semaphore (3) - 수정, 테스트 해보기

반응형

패치를 작성하게 된 이유

semaphore를 분석하다가, struct semaphore의 lock이 좀 성긴 (coarse 한) 것 같아서, semaphore_waiter을 관리하는 락을 reader / writer 락으로 분리해서 성능을 테스트 해봤다. 락을 현재 획득한 프로세스가 writer, wait_list에서 대기중인 프로세스가 reader이므로 rwlock_t를 사용하면 더 빨라질거라고 생각했다. 패치 파일은 아래와 같다.

 

0001-kernel-locking-Introduce-rwlock_t-to-wait_list-of-semaphore.patch
0.01MB

benchmark

이 패치를 메인테이너한테 받아달라고 설득하려면, 이게 성능을 개선한다는 지표가 필요했다. 그래서 간단한 테스트 코드를 작성해보았다. 테스트는 make bzImage, make install로 이미지 설치, 빌드 후에 해당 커널로 부팅해서 모듈을 실행했다.

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/semaphore.h>
#include <linux/kthread.h>
#include <linux/slab.h>

DEFINE_SEMAPHORE(sem);
int count;
int n_seconds = 30;
int n_threads = 10;
struct task_struct **tasks;

module_param(n_seconds, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
module_param(n_threads, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);

static int func(void *arg)
{
	while (!kthread_should_stop()) {
		down_interruptible(&sem);
		count++;
		up(&sem);
	}
	return 0;
}

int __init semtest_init(void)
{
	int i;
	unsigned long delay;
	int score;

	if ((tasks = kmalloc(sizeof(struct task_struct *) * n_threads, GFP_KERNEL)) == NULL)
		return 0;

	printk(KERN_INFO "start init\n");
	down_interruptible(&sem);
	for (i = 0; i < n_threads; i++) {
		tasks[i] = kthread_run(&func, NULL, "example");
	}
	delay = jiffies + n_seconds * HZ;
	up(&sem);

	printk(KERN_INFO "waiting for threads...\n");

	while (time_before(jiffies, delay));
	score = count / n_seconds / n_threads;
	printk(KERN_INFO "count = %d\n", count);
	printk(KERN_INFO "score = count / n_threads / n_seconds = %d\n", score);

	for (i = 0; i < n_threads; i++) {
		kthread_stop(tasks[i]);
	}

	kfree(tasks);
	return 0;
}

void __exit semtest_exit(void)
{
}

module_init(semtest_init);
module_exit(semtest_exit);

MODULE_AUTHOR("Hyeonggon Yoo <42.hyeyoo@gmail.com>");
MODULE_DESCRIPTION("simple module that tests performance of semaphore");
MODULE_LICENSE("GPL");

패치 적용 전
패치 적용 후

아쉽게도 성능이 올라가긴 커녕 나빠졌다. 정확한 이유는 알 수 없지만 아무래도 sleep을 하면서 기다리다 보니까 락을 획득하는 데에 경쟁이 그렇게 심하지 않거나, 새로운 락을 추가해서 사용하는 오버헤드가 더 큰 것일지도 모른다. 

panic!

코드를 수정하면서, 실수로 list_del을 중복해서 호출했는데, 바로 panic이 떠버려서 부팅이 되지 않았다. 디버깅할 방법도 없고 메시지를 스크롤해서 올릴 수도 없어서 매우 불편했다. 좀 더 편하게 디버깅할 방법을 찾아봐야겠다.

 

  • BlogIcon hygoni 2021.04.24 01:10 신고

    어 패치 잘못올렸다

  • 양원혁 2021.04.26 10:46

    안녕하세요

    문c 블로그를 잠깐 방문하니 어디서 낯익은 이름이 보이더라구요ㅎㅎ 메일링 리스트에서 본 분이란 걸 깨닫고
    해당 블로그에 방문하게 되었습니다.

    세마포의 count는 semaphore.lock을 통해 일관성을 유지하고, list 부분은 다른 lock을 사용해 일관성을 유지하여,
    하나의 큰 임계 구간을 두 개의 작은 임계 구간으로 나눈 것이 패치의 컨셉이라 이해했습니다.

    그런 점에서 패치를 읽고 몇 가지 알쏭달쏭한 부분이 있는데요,

    1) waiter.up을 read lock을 사용해 읽는다는 점
    2) timeout 또는 interrupt일 때, write lock을 통해 데이터 일관성을 유지하지 않는다는 점.
    3) 굳이 rwlock을 사용한다는 점.(read가 많이 발생하고, write가 적게 발생하는 상황이 맞는가?)

    • BlogIcon hygoni 2021.04.26 11:33 신고

      연습용으로 쓴 것이라 누가 읽어줄거라고 생각을 못했는데, 유심히 읽어주셔서 감사합니다.

      우선 2번에 대해서는 생각을 못해서 제가 데이터 일관성을 지키지 못한 것이 맞습니다. 코드를 짤때 생각하지 못한 부분이네요.

    • BlogIcon hygoni 2021.04.26 11:34 신고

      https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbdeTHy%2Fbtq3q5YAtKU%2Fo3pALJPDWPg5K4RXQkRJqk%2Fimg.jpg

    • BlogIcon hygoni 2021.04.26 11:37 신고

      rwlock을 사용한 이유는 위의 그림의 상황에서, 현재 자신이 깨어났는지 확인하는 프로세스와 (waiter.up이 참인지 read)

      현재 락을 획득하여 다른 프로세스를 깨우는 (waiter.up = true로 바꾸는 write) 프로세스 로 reader와 writer로 분리가 되는 상황이라고 생각했습니다.

    • BlogIcon hygoni 2021.04.26 11:38 신고

      (물론 결과는 그닥 좋지 못했지만요)

    • BlogIcon hygoni 2021.04.26 11:40 신고

      사실 그런걸 떠나서 실수로 Oops를 고치기 전의 올린 것도 있고,

      말씀해주신 부분 생각해보고 다시 고쳐보면 좋을 것 같네요, 감사합니다

  • 양원혁 2021.04.26 14:50

    > rwlock을 사용한 이유는 위의 그림의 상황에서, 현재 자신이 깨어났는지 확인하는 프로세스와 (waiter.up이 참인지 read)

    > 현재 락을 획득하여 다른 프로세스를 깨우는 (waiter.up = true로 바꾸는 write) 프로세스 로 reader와 writer로 분리가 되는 상황이라고 생각했습니다.

    네 상황은 read task 1개와 write task 1개로 나뉘네요. 다만, rwlock의 퍼포먼스를 기대하기 어려운 상황인 것 같네요..ㅠㅠ

    문득, waiter.up에 대한 동기화가 필요한가 싶기도 한데ㅎ, 다양한 경쟁 상황들을 한 번 생각해봐야겠군요..

    • BlogIcon hygoni 2021.04.26 14:57 신고

      맞습니다 ㅋㅋㅋ ㅠㅠ 고쳐도 별로 성능이 좋아지진 않더군요.

    • BlogIcon hygoni 2021.04.26 14:59 신고

      그래도 혼자 공부하면 심심한데 이렇게 같이 이야기해주셔서 즐겁네요!

    • BlogIcon 양원혁 2021.04.26 16:29

      헉 혼자서 쉽지 않을텐데..
      저도 재밌게 이야기했어요 종종 시간날 때 들릴게요~

      저도 혼자 커널 공부하다가, 커널 스터디에 참가했는데 재밌더라구요
      아실지도 모르겠지만 iamroot에서 18기 모집 중인데 관심이 있으실지 모르겠네요..

      이번 기수에는 문c 블로그의 문영일님 다시 참가하시던데..

    • BlogIcon hygoni 2021.04.26 16:31 신고

      iamroot..!!!! 저도 참여하고 싶은데 ㅠㅠㅠ 6월쯤에 곧 군대에 갑니다....

      그래서 뭔가 신청하기가 좀 그렇네요 ㅠㅠㅠㅠ

    • BlogIcon 양원혁 2021.04.26 16:53

      헉.. 저런... 건강히 잘 다녀오세요...