요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.
1. 요약·해설
원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.
2. 영어 원문 전체
번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.
원문 전체 펼치기
========================
MMC Asynchronous Request
========================
Rationale
=========
How significant is the cache maintenance overhead?
It depends. Fast eMMC and multiple cache levels with speculative cache
pre-fetch makes the cache overhead relatively significant. If the DMA
preparations for the next request are done in parallel with the current
transfer, the DMA preparation overhead would not affect the MMC performance.
The intention of non-blocking (asynchronous) MMC requests is to minimize the
time between when an MMC request ends and another MMC request begins.
Using mmc_wait_for_req(), the MMC controller is idle while dma_map_sg and
dma_unmap_sg are processing. Using non-blocking MMC requests makes it
possible to prepare the caches for next job in parallel with an active
MMC request.
MMC block driver
================
The mmc_blk_issue_rw_rq() in the MMC block driver is made non-blocking.
The increase in throughput is proportional to the time it takes to
prepare (major part of preparations are dma_map_sg() and dma_unmap_sg())
a request and how fast the memory is. The faster the MMC/SD is the
more significant the prepare request time becomes. Roughly the expected
performance gain is 5% for large writes and 10% on large reads on a L2 cache
platform. In power save mode, when clocks run on a lower frequency, the DMA
preparation may cost even more. As long as these slower preparations are run
in parallel with the transfer performance won't be affected.
Details on measurements from IOZone and mmc_test
================================================
https://wiki.linaro.org/WorkingGroups/Kernel/Specs/StoragePerfMMC-async-req
MMC core API extension
======================
There is one new public function mmc_start_req().
It starts a new MMC command request for a host. The function isn't
truly non-blocking. If there is an ongoing async request it waits
for completion of that request and starts the new one and returns. It
doesn't wait for the new request to complete. If there is no ongoing
request it starts the new request and returns immediately.
MMC host extensions
===================
There are two optional members in the mmc_host_ops -- pre_req() and
post_req() -- that the host driver may implement in order to move work
to before and after the actual mmc_host_ops.request() function is called.
In the DMA case pre_req() may do dma_map_sg() and prepare the DMA
descriptor, and post_req() runs the dma_unmap_sg().
Optimize for the first request
==============================
The first request in a series of requests can't be prepared in parallel
with the previous transfer, since there is no previous request.
The argument is_first_req in pre_req() indicates that there is no previous
request. The host driver may optimize for this scenario to minimize
the performance loss. A way to optimize for this is to split the current
request in two chunks, prepare the first chunk and start the request,
and finally prepare the second chunk and start the transfer.
Pseudocode to handle is_first_req scenario with minimal prepare overhead::
if (is_first_req && req->size > threshold)
/* start MMC transfer for the complete transfer size */
mmc_start_command(MMC_CMD_TRANSFER_FULL_SIZE);
/*
* Begin to prepare DMA while cmd is being processed by MMC.
* The first chunk of the request should take the same time
* to prepare as the "MMC process command time".
* If prepare time exceeds MMC cmd time
* the transfer is delayed, guesstimate max 4k as first chunk size.
*/
prepare_1st_chunk_for_dma(req);
/* flush pending desc to the DMAC (dmaengine.h) */
dma_issue_pending(req->dma_desc);
prepare_2nd_chunk_for_dma(req);
/*
* The second issue_pending should be called before MMC runs out
* of the first chunk. If the MMC runs out of the first data chunk
* before this call, the transfer is delayed.
*/
dma_issue_pending(req->dma_desc);
3. 한국어 전문 번역
영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.
비동기 요청의 필요성
1-22빠른 eMMC, 여러 cache level, speculative prefetch가 결합되면 cache maintenance 비용은 상대적으로 커질 수 있습니다. 다음 요청의 DMA 준비를 현재 전송과 병렬로 수행하면 이 비용이 MMC 성능을 막지 않습니다.
Non-blocking MMC request의 목적은 한 요청이 끝난 뒤 다음 요청이 시작될 때까지의 빈 시간을 최소화하는 것입니다.
`mmc_wait_for_req()`를 사용하면 `dma_map_sg()`와 `dma_unmap_sg()` 처리 중 controller가 유휴 상태가 됩니다. 비동기 요청은 활성 MMC 전송과 병렬로 다음 작업의 cache를 준비하게 합니다.
DMA 준비를 전송 구간과 겹쳐 controller 유휴 시간을 줄입니다.
========================
MMC Asynchronous Request
========================
Rationale
=========
How significant is the cache maintenance overhead?
It depends. Fast eMMC and multiple cache levels with speculative cache
pre-fetch makes the cache overhead relatively significant. If the DMA
preparations for the next request are done in parallel with the current
transfer, the DMA preparation overhead would not affect the MMC performance.
The intention of non-blocking (asynchronous) MMC requests is to minimize the
time between when an MMC request ends and another MMC request begins.
Using mmc_wait_for_req(), the MMC controller is idle while dma_map_sg and
dma_unmap_sg are processing. Using non-blocking MMC requests makes it
possible to prepare the caches for next job in parallel with an active
MMC request.
MMC block driver와 성능
23-41MMC block driver의 `mmc_blk_issue_rw_rq()`는 non-blocking 방식으로 만들어졌습니다.
처리량 증가는 요청 준비 시간, 주로 `dma_map_sg()`와 `dma_unmap_sg()`, 그리고 memory 속도에 비례합니다. MMC/SD가 빠를수록 준비 시간의 비중이 커집니다.
L2 cache platform에서 예상되는 대략적인 성능 향상은 대용량 write 5%, 대용량 read 10%입니다. 절전 모드처럼 clock이 느릴 때 DMA 준비 비용은 더 커질 수 있지만, 전송과 병렬로 수행하면 성능에는 영향을 주지 않습니다.
IOZone과 `mmc_test` 측정 상세는 문서에 적힌 Linaro StoragePerfMMC async request 자료에서 확인할 수 있습니다.
MMC block driver
================
The mmc_blk_issue_rw_rq() in the MMC block driver is made non-blocking.
The increase in throughput is proportional to the time it takes to
prepare (major part of preparations are dma_map_sg() and dma_unmap_sg())
a request and how fast the memory is. The faster the MMC/SD is the
more significant the prepare request time becomes. Roughly the expected
performance gain is 5% for large writes and 10% on large reads on a L2 cache
platform. In power save mode, when clocks run on a lower frequency, the DMA
preparation may cost even more. As long as these slower preparations are run
in parallel with the transfer performance won't be affected.
Details on measurements from IOZone and mmc_test
================================================
https://wiki.linaro.org/WorkingGroups/Kernel/Specs/StoragePerfMMC-async-req
MMC core와 host 확장
42-62새 public function은 `mmc_start_req()`입니다. Host에 새 MMC command request를 시작합니다.
이 함수는 완전히 non-blocking은 아닙니다. 진행 중인 async request가 있으면 그 완료를 기다린 뒤 새 요청을 시작하고 반환하지만, 새 요청 자체의 완료는 기다리지 않습니다. 진행 중인 요청이 없으면 새 요청을 시작하고 즉시 반환합니다.
`mmc_host_ops`에는 host driver가 구현할 수 있는 optional member `pre_req()`와 `post_req()`가 있습니다. 실제 `mmc_host_ops.request()` 호출 전후로 작업을 이동하기 위한 hook입니다.
DMA 사용 시 `pre_req()`는 `dma_map_sg()`와 DMA descriptor 준비를 수행하고, `post_req()`는 `dma_unmap_sg()`를 수행할 수 있습니다.
이전 요청 완료와 새 요청 시작 사이에 host 준비 및 정리 hook을 배치합니다.
MMC core API extension
======================
There is one new public function mmc_start_req().
It starts a new MMC command request for a host. The function isn't
truly non-blocking. If there is an ongoing async request it waits
for completion of that request and starts the new one and returns. It
doesn't wait for the new request to complete. If there is no ongoing
request it starts the new request and returns immediately.
MMC host extensions
===================
There are two optional members in the mmc_host_ops -- pre_req() and
post_req() -- that the host driver may implement in order to move work
to before and after the actual mmc_host_ops.request() function is called.
In the DMA case pre_req() may do dma_map_sg() and prepare the DMA
descriptor, and post_req() runs the dma_unmap_sg().
첫 요청 최적화
63-98연속 요청의 첫 요청은 앞선 전송이 없으므로 준비 작업을 이전 전송과 병렬화할 수 없습니다. `pre_req()`의 `is_first_req` 인자가 이 상황을 알립니다.
Host driver는 성능 손실을 줄이기 위해 요청을 두 chunk로 나눌 수 있습니다. 첫 chunk를 준비하고 전체 크기의 MMC command를 시작한 뒤, command 처리 중 두 번째 chunk를 준비합니다.
첫 chunk 준비 시간은 MMC command 처리 시간과 비슷해야 합니다. 준비가 더 오래 걸리면 전송이 지연되므로 첫 chunk는 최대 4 KiB 정도로 추정합니다.
첫 descriptor의 `dma_issue_pending()` 후 두 번째 chunk를 준비하고 다시 issue합니다. 두 번째 호출은 MMC가 첫 data chunk를 모두 소비하기 전에 이루어져야 합니다.
첫 요청의 DMA 준비를 command 처리와 겹치고 두 chunk를 끊김 없이 공급합니다.
Optimize for the first request
==============================
The first request in a series of requests can't be prepared in parallel
with the previous transfer, since there is no previous request.
The argument is_first_req in pre_req() indicates that there is no previous
request. The host driver may optimize for this scenario to minimize
the performance loss. A way to optimize for this is to split the current
request in two chunks, prepare the first chunk and start the request,
and finally prepare the second chunk and start the transfer.
Pseudocode to handle is_first_req scenario with minimal prepare overhead::
if (is_first_req && req->size > threshold)
/* start MMC transfer for the complete transfer size */
mmc_start_command(MMC_CMD_TRANSFER_FULL_SIZE);
/*
* Begin to prepare DMA while cmd is being processed by MMC.
* The first chunk of the request should take the same time
* to prepare as the "MMC process command time".
* If prepare time exceeds MMC cmd time
* the transfer is delayed, guesstimate max 4k as first chunk size.
*/
prepare_1st_chunk_for_dma(req);
/* flush pending desc to the DMAC (dmaengine.h) */
dma_issue_pending(req->dma_desc);
prepare_2nd_chunk_for_dma(req);
/*
* The second issue_pending should be called before MMC runs out
* of the first chunk. If the MMC runs out of the first data chunk
* before this call, the transfer is delayed.
*/
dma_issue_pending(req->dma_desc);
요약과 해설
mmc-async-req.rst:1-98비동기 MMC request는 DMA map/unmap을 활성 전송과 겹치고 첫 요청을 두 chunk로 준비해 controller 유휴 시간을 줄입니다.