libata: get rid of ATA_MAX_QUEUE loop in ata_qc_complete_multiple()
PATCH 1/1 libata: get rid of ATA_MAX_QUEUE loop in ata_qc_complete_multiple()
Hi,
We very rarely (if ever) complete more than one command in the sactive mask at the time, even for extremely high IO rates. So looping over the entire range of possible tags is pointless, instead use __ffs() to just find the completed tags directly.
--- drivers/ata/libata-core.c | 15 +++++++++------ 1 files changed, 9 insertions(+), 6 deletions(-)
drivers/ata/libata-core.c +9 -6
@@ -5027,9 +5027,9 @@ void ata_qc_complete(struct ata_queued_cmd *qc)*/ int ata_qc_complete_multiple (struct ata_port *ap,u32 qc_active) { +unsigned int i =0 ;int nr_done =0 ;u32 done_mask; -int i; done_mask = ap->qc_active ^ qc_active;
@@ -5039,16 +5039,19 @@ int ata_qc_complete_multiple(struct ata_port *ap, u32 qc_active)return -EINVAL ; } -for (i =0 ; i <ATA_MAX_QUEUE ; i++) { +while (done_mask) {struct ata_queued_cmd *qc; +unsigned int next =__ffs (done_mask); -if (!(done_mask & (1 << i))) -continue ; - -if ((qc =ata_qc_from_tag (ap, i))) { + qc =ata_qc_from_tag (ap, i + next); +if (qc) {ata_qc_complete (qc); nr_done++; } +if (++next >=ATA_MAX_QUEUE ) +break ; + i += next; + done_mask >>= next; }return nr_done;
Signature · 5 lines
1.6.3.rc0.1.gf800 -- Jens Axboe
Hello, Jens.
Quoted 10 lines · Jens Axboe
drivers/ata/libata-core.c +2
-2@@ -5039,16 +5039,19 @@ int ata_qc_complete_multiple(struct ata_port *ap, u32 qc_active)return -EINVAL ; } -for (i =0 ; i <ATA_MAX_QUEUE ; i++) { +while (done_mask) {struct ata_queued_cmd *qc; +unsigned int next =__ffs (done_mask); -if (!(done_mask & (1 << i)))
drivers/ata/libata-core.c int ata_qc_complete_multiple(struct ata_port *ap, u32 qc_active) · line 5052
Quoted 10 lines
drivers/ata/libata-core.c +4
-3-continue ; - -if ((qc =ata_qc_from_tag (ap, i))) { + qc =ata_qc_from_tag (ap, i + next); +if (qc) {ata_qc_complete (qc); nr_done++; } +if (++next >=ATA_MAX_QUEUE ) +break ;
Given that __ffs doesn't care how far the first bit is on most archs (even the generic one), I think it would be simpler and more efficient to simply do done_mask &= ~(1 << i) and loop without adding to index and shifting.
Thanks.
Signature · 1 line
tejun
Quoted 12 lines · Tejun Heo
Hello, Jens.
Quoted 9 lines · Jens Axboe
drivers/ata/libata-core.c +2
-1@@ -5039,16 +5039,19 @@ int ata_qc_complete_multiple(struct ata_port *ap, u32 qc_active)return -EINVAL ; } -for (i =0 ; i <ATA_MAX_QUEUE ; i++) { +while (done_mask) {struct ata_queued_cmd *qc; +unsigned int next =__ffs (done_mask);
Quoted 16 lines
drivers/ata/libata-core.c int ata_qc_complete_multiple(struct ata_port *ap, u32 qc_active) · line 5052
Quoted 11 lines
drivers/ata/libata-core.c +4
-4-if (!(done_mask & (1 << i))) -continue ; - -if ((qc =ata_qc_from_tag (ap, i))) { + qc =ata_qc_from_tag (ap, i + next); +if (qc) {ata_qc_complete (qc); nr_done++; } +if (++next >=ATA_MAX_QUEUE ) +break ;Given that
__ffsdoesn't care how far the first bit is on most archs (even the generic one), I think it would be simpler and more efficient to simply dodone_mask&= ~(1 << i) and loop without adding to index and shifting.
It would be easier to read as well, agree. I'll repost it in 2 secs.
Signature · 1 line
Jens Axboe