thread 관리 data sturcture 및 system에서 비동기 I/O 관리 방법

kyungminLim·2024년 5월 23일
0

linux system software 에서 trace replay를 통한 성능 측정에 필요했던 data structure를 정리하도록 하겠다.

thread_info_t (thread 정보 저장 data structure)

struct thread_info_t {
    int tid;
    pthread_mutex_t mutex;
    pthread_cond_t cond_main, cond_sub;
    io_context_t io_ctx;
    struct io_event events[MAX_QDEPTH];

    int queue_depth;
    int queue_count;
    int active_count;
    int fd;
    int fsync_period;

    struct io_job *th_jobs[MAX_QDEPTH];
    void *th_buf[MAX_QDEPTH];
    int buf_cur;

    struct io_stat_t io_stat;

    struct trace_info_t *trace;

    int done;
};
  • 'tid' : thread_ ID
  • 'mutex' : thread 간 동기화를 위한 mutex
  • 'cond_main', 'cond_sub' : main thread와 sub thread 간의 조건 변수이다.
  • 'io_ctx' : I/O context이다.
  • 'events' : I/O event array
  • 'queue_depth' : queue_depth
  • 'queue_count' : queue내에 있는 작업의 수이다.
  • 'active_count' : active job의 수
  • 'fd' : file descriptor
  • 'fsync_period' : 파일 동기화 주기이다.
  • 'th_jobs' : I/O 작업 배열이다.
  • 'th_buf' : I/O buffer 배열
  • 'buf_cur' : 현재 buffer index이다.
  • 'io_stat' : I/O 통계 정보를 저장하는 구조체이다.
  • 'trace' : trace 정보 포인터이다.
  • 'done' : 작업 완료 상태를 나타낸다.

'io_job' data structure

struct io_job {
    struct iocb iocb;
    struct flist_head list;
    struct timeval start_time, stop_time;
    long long offset; // in bytes
    size_t bytes;
    int rw; // is read
    char *buf;
};
  • 'iocb' : I/O control block (제어 블록)
  • 'list' : 연결 리스트의 헤더
  • 'start_time, stop_time' : 작업 시작 시간과 종료 시간이다.
  • 'offset' : I/O 작업의 byte offset이다.
  • 'bytes' : I/O 작업의 byte 수이다.
  • 'rw' : rw 작업인지 여부를 나타낸다.
  • 'buf' : I/O buffer이다.

비동기 I/O 작업 관리를 위한 'io_context_t io_ctx'

'io_ctx'는 'io_context_t' type 변수로, 비동기 I/O (Asynchronous I/O) 작업을 관리하는 context를 나타낸다. 이 context는 kernel과 user space 사이에서 비동기 I/O 요청을 효율적으로 처리하기 위해 사용된다. Linux에서 비동기 I/O는 'io_submit', 'io_getevents'와 같은 system call을 통해 비동기 I/O 작업을 수행할 수 있게 해준다.

  1. 비동기 I/O 관리
  • 'io_ctx'는 비동기 I/O 작업의 상태를 추적하고 관리하는데 사용되고 이를 통해 여러 비동기 I/O 요청을 queueing하고, 완료 이벤트를 효율적으로 처리할 수 있다.
  1. 작업 제출
  • 비동기 I/O 요청은 'io_submit' system call을 통해 제출된다. 이때 'io_ctx'는 해당 요청들이 어느 context에서 관리될지를 지정한다.
  1. 이벤트 수집
  • 비동기 I/O 작업이 완료되면, 'io_getevents' system call을 사용해서 완료된 이벤트를 수집한다. 이때, 'io_ctx'는 어떤 컨텍스트의 이벤트를 수집할지를 지정한다.
  1. 동시성 향상
  • 비동기 I/O는 blocking 없이 I/O 작업을 수행할 수 있게 해줘서, CPU와 I/O 장치의 병렬 처리를 가능하게 해준다. 이를 통해 system의 전반적인 동시성과 성능을 향상시킬 수 있다.

사용 예제

#include <libaio.h>

/* context 초기화
	'io_setup' system call을 통해 비동기 I/O context를 초기화한다. 'MAX_EVENTS'는 context에서 동시에 처리할 수 있는 최대 I/O events 수를 지정한다.
*/
io_context_t io_ctx;
memset(&io_ctx, 0, sizeof(io_ctx));
int ret = io_setup(MAX_EVENTS, &io_ctx);
if(ret < 0) {
	perror("io_setup");
    return -1;
}

/* I/O 작업 submit
	'io_prep_pread' 함수를 사용해서 읽기 작업을 준비하고, 'io_submit'을 통해 I/O 요청을 제출한다.
*/
struct iocb cb;
struct iocb *cbs[1];

io_prep_pread(&cb, fd, buffer, buffer_size, offset);
cbs[0] = &cb;

ret = io_submit(io_ctx, 1, cbs);
if (ret < 0) {
	perror("io_submit");
    return -1;
}

/* 완료된 I/O 이벤트 수집
	'io_getevents'를 사용해서 완료된 I/O 이벤트를 수집한다. 'min_nr'와 'max_nr'는 수집할 최소 및 최대 이벤트 수를 지정한다.
*/
struct io_event events[MAX_EVENTS];
ret = io_getevents(io_ctx, min_nr, max_nr, events, NULL);
if (ret < 0) {
	perror("io_getevents");
    return -1;
}

for (int i=0; i < ret; i++) {
	// event 처리 코드
}

/* context 해제 
	모든 작업이 완료되면 'io_destroy'를 사용해서 비동기 I/O context를 해제한다.
*/
ret = io_destroy(io_ctx);
if (ret < 0) {
	perror("io_destroy");
    return -1;
}

요약하자면 'io_ctx'는 비동기 I/O 작업을 관리하는 context로, I/O 요청의 제출 및 완료 이벤트의 수집을 효율적으로 처리하기 위해 사용된다. 이를 통해 블로킹 없이 비동기적으로 I/O 작업을 수행할 수 있으며, 시스템의 동시성과 성능을 향상시킬 수 있다.

0개의 댓글