2011-08-02 14 views
9

私はカーネルの非同期IO関数(posix aioではない)をテストしており、どのように動作するかを調べようとしています。以下のコードは、O_DIRECTを使用して開いたファイルに配列を繰り返し書き込む完全なプログラムです。コールバック関数にエラーが発生しました。「write missing bytesが1024になると期待しています」(work_done()のfprintf文を参照)。linuxカーネルaioの機能

カーネルAIOに精通していない方のため

、以下のコードは、次の操作を実行します。

  1. 初期にいくつかの構造体
  2. (io_prep_pwrite)
  3. IO要求(io_submit)用
  4. チェックを提出AIOを準備イベント完了(io_getevents)
  5. すべてが正常に実行されたかどうかを確認するコールバック関数を呼び出します。

手順5でエラーが発生します.O_DIRECTを使用してファイルを開いても、正常に動作しますが、非同期書き込みを行う目的には勝っています。 誰かが私が間違っていることを教えてもらえますか?これはカーネルaioの正しい使い方ですか?例えば、コールバックの正しい使い方ですか? O_DIRECTの使用に制限はありますか?

私は 'gccの-Wall test.cの-laio' 事前に

感謝を使用してコンパイルします。

/* 
* File: myaiocp.c 
* Author: kmehta 
* 
* Created on July 11, 2011, 12:50 PM 
* 
* 
* Testing kernel aio. 
* Program creates a 2D matrix and writes it multiple times to create a file of desired size. 
* Writes are performed using kernel aio functions (io_prep_pwrite, io_submit, etc.) 
*/ 
#define _GNU_SOURCE 
#define _XOPEN_SOURCE 600 

#include <stdio.h> 
#include <stdlib.h> 
#include <getopt.h> 
#include <pthread.h> 
#include <fcntl.h> 
#include <string.h> 
#include <sys/uio.h> 
#include <sys/time.h> 
#include <omp.h> 
#include <unistd.h> 
#include <sys/types.h> 
#include <sys/stat.h> 
#include <errno.h> 
#include <libaio.h> 

char ** buf; 
long seg_size; 
int seg_rows; 
double total_size; 
char * filename; 
static int wait_count = 0; 

void io_task(); 
void cleanup(); 
void allocate_2D_matrix(int[]); 
int file_open(char *); 
void wr_done(io_context_t ctx, struct iocb* iocb, long res, long res2); 

int main(int argc, char **argv) { 
    total_size = 1048576;  //1MB 
    seg_size = 1024;   //1kB 
    seg_rows = 1024; 
    filename = "aio.out"; 

    int dims[] = {seg_rows, seg_size}; 
    allocate_2D_matrix(dims); //Creates 2D matrix 

    io_task(); 
    cleanup(); 

    return 0; 
} 

/* 
* Create a 2D matrix 
*/ 
void allocate_2D_matrix(int dims[2]) { 
    int i; 
    char *data; 

    //create the matrix 
    data = (char *) calloc(1, dims[0] * dims[1] * sizeof (char)); 
    if (data == NULL) { 
     printf("\nCould not allocate memory for matrix.\n"); 
     exit(1); 
    } 

    buf = (char **) malloc(dims[0] * sizeof (char *)); 
    if (buf == NULL) { 
     printf("\nCould not allocate memory for matrix.\n"); 
     exit(1); 
    } 

    for (i = 0; i < dims[0]; i++) { 
     buf[i] = &(data[i * dims[1]]); 
    } 
} 

static void io_error(const char *func, int rc) 
{ 
    if (rc == -ENOSYS) 
     fprintf(stderr, "AIO not in this kernel\n"); 
    else if (rc < 0) 
     fprintf(stderr, "%s: %s\n", func, strerror(-rc)); 
    else 
     fprintf(stderr, "%s: error %d\n", func, rc); 

    exit(1); 
} 

/* 
* Callback function 
*/ 
static void work_done(io_context_t ctx, struct iocb *iocb, long res, long res2) 
{ 

    if (res2 != 0) { 
     io_error("aio write", res2); 
     } 

     if (res != iocb->u.c.nbytes) { 
      fprintf(stderr, "write missed bytes expect %lu got %ld\n", 
        iocb->u.c.nbytes, res2); 
      exit(1); 
     } 
     wait_count --; 
     printf("%d ", wait_count); 
} 

/* 
* Wait routine. Get events and call the callback function work_done() 
*/ 
int io_wait_run(io_context_t ctx, long iter) 
{ 
     struct io_event events[iter]; 
     struct io_event *ep; 
     int ret, n; 

     /* 
     * get up to aio_maxio events at a time. 
     */ 
     ret = n = io_getevents(ctx, iter, iter, events, NULL); 
     printf("got %d events\n", n); 
     /* 
     * Call the callback functions for each event. 
     */ 
     for (ep = events ; n-- > 0 ; ep++) { 
      io_callback_t cb = (io_callback_t)ep->data ; struct iocb *iocb = ep->obj ; cb(ctx, iocb, ep->res, ep->res2); 
     } 
     return ret; 
} 

void io_task() { 
    long offset = 0; 
    int bufIndex = 0; 

    //Open file 
    int fd = file_open(filename); 

    //Initialize structures 
    long i; 
    long iter = total_size/seg_size; //No. of iterations to reach desired file size (total_size) 
    io_context_t myctx; 
    if(0 != io_queue_init(iter, &myctx)) 
    { 
     perror("Could not initialize io queue"); 
     exit(EXIT_FAILURE); 
    } 
    struct iocb * ioq[iter]; 

    //loop through iter times to reach desired file size 
    for (i = 0; i < iter; i++) { 
     struct iocb *io = (struct iocb*) malloc(sizeof (struct iocb)); 
     io_prep_pwrite(io, fd, buf[bufIndex], seg_size, offset); 
     io_set_callback(io, work_done); 
     ioq[i] = io; 

     offset += seg_size; 
     bufIndex ++; 
     if (bufIndex > seg_rows - 1) //If entire matrix written, start again from index 0 
      bufIndex = 0; 
    } 

    printf("done preparing. Now submitting..\n"); 
    if(iter != io_submit(myctx, iter, ioq)) 
    { 
     perror("Failure on submit"); 
     exit(EXIT_FAILURE); 
    } 

    printf("now awaiting completion..\n"); 
    wait_count = iter; 
    int res; 

    while (wait_count) { 
     res = io_wait_run(myctx, iter); 
     if (res < 0) 
      io_error("io_wait_run", res); 
    } 

    close(fd); 
} 

void cleanup() { 
    free(buf[0]); 
    free(buf); 
} 

int file_open(char *filename) { 
    int fd; 
    if (-1 == (fd = open(filename, O_DIRECT | O_CREAT | O_WRONLY | O_TRUNC, 0666))) { 
     printf("\nError opening file. \n"); 
     exit(-1); 
    } 

    return fd; 
} 

答えて

7

まず、libaioの代わりに、POSIX aioを使用して良い仕事。

O_DIRECTの使用に制限はありますか?

私はこれが本当の問題である100%わからないんだけど、O_DIRECT(TLPIからほとんど引用)いくつかの要件があります。

データバッファが転送されて
  • がメモリ上に整列しなければなりませんブロックサイズの倍数である境界(posix_memalign
  • データ転送が開始されるファイルまたはデバイスのオフセットは、ブロックサイズの倍数である必要があります。
  • 転送されるデータの長さブロックサイズの倍数でなければなりません

一見、私はあなたがのメモリを整列させるための注意を払っていないのが分かります。

O_DIRECTを使用してファイルを開かないと、問題なく動作しますが、 は非同期書き込みを行う目的に勝ります。

これはそうではありません。非同期I/Oは、O_DIRECTなしでうまくいきます(例えば、システムコールの数をスラッシュしたものと考える)。

+0

TLPI参照の場合+1。これまでに一番素晴らしい本です。 – hari

+0

@cnicutar素晴らしい。それはそれを修正した。しかし、質問のカップル: 1。なぜposix aioの代わりにlibaioを使うことを提案しましたか?私はposix aioで多くの経験を持っていないので、私は知らない。 2.なぜ非同期I/OはO_DIRECTなしでうまく動作しますか?どのようにしてそれを減らすのですか?システムコールの?実際には、カーネルのバッファリングをバイパスするので、O_DIRECTはより効率的だと思いました。 – jitihsk

+1

'mmap'はおそらく' posix_memalign'よりも4kアライメントされたメモリを得る良い方法です。後者は、必要な簿記の数バイトのために割り当ての開始時に必ず4kを無駄にしなければならないでしょう。これはページの粒度に割り当てます(あなたが 'mmix'を経由してリクエストに' posix_memalign' )。 –

関連する問題