powerpc: Optimize copyinstr() to avoid repeatedly mapping user strings

Currently copyinstr() uses fubyte() to read each byte from userspace.
However, this means that for each byte, it calls pmap_map_user_ptr() to
map the string into memory.  This is needlessly wasteful, since the
string will rarely ever cross a segment boundary.  Instead, map a
segment at a time, and copy as much from that segment as possible at a
time.

Measured with the HPT pmap on powerpc64, this saves roughly 8% time on
buildkernel, and 5% on buildworld, in wallclock time.
This commit is contained in:
Justin Hibbits 2020-06-04 13:15:15 -05:00 committed by Piotr Kubaj
parent adf79abc35
commit 6260bfb087

View File

@ -236,31 +236,51 @@ REMAP(copyin)(const void *udaddr, void *kaddr, size_t len)
int
REMAP(copyinstr)(const void *udaddr, void *kaddr, size_t len, size_t *done)
{
struct thread *td;
pmap_t pm;
jmp_buf env;
const char *up;
char *kp;
size_t l;
int rv, c;
char *kp, *p;
size_t i, l, t;
int rv;
td = curthread;
pm = &td->td_proc->p_vmspace->vm_pmap;
t = 0;
rv = ENAMETOOLONG;
td->td_pcb->pcb_onfault = &env;
if (setjmp(env)) {
rv = EFAULT;
goto done;
}
kp = kaddr;
up = udaddr;
rv = ENAMETOOLONG;
for (l = 0; len-- > 0; l++) {
if ((c = fubyte(up++)) < 0) {
while (len > 0) {
if (pmap_map_user_ptr(pm, up, (void **)&p, len, &l)) {
rv = EFAULT;
break;
goto done;
}
if (!(*kp++ = c)) {
l++;
rv = 0;
break;
for (i = 0; len > 0 && i < l; i++, t++, len--) {
if ((*kp++ = *p++) == 0) {
i++, t++;
rv = 0;
goto done;
}
}
up += l;
}
done:
td->td_pcb->pcb_onfault = NULL;
if (done != NULL) {
*done = l;
*done = t;
}
return (rv);