lkml.org 
[lkml]   [2000]   [Mar]   [18]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
SubjectRe: Linux Jobs: Update
   Date: Tue, 14 Mar 2000 10:46:00 +1300
From: Chris Wedgwood <cw@f00f.org>

> Anyways please let me know the results of the above experiment
> on FreeBSD. Their memcpy() is not twice as fast as ours :-)

The results are the same -- all I can think of now are hardware
differences. The machines are bot PPro200's -- but perhaps one has
superior memory bandwidth or something?

Ok, the difference is that they are doing half as many memcpy's as us
for large pipe writes. This should make Linux push bulk pipe data as
fast as FreeBSD. Give it a try, let me know how things look now ok?

--- include/linux/pipe_fs_i.h.~1~ Wed Dec 15 08:34:43 1999
+++ include/linux/pipe_fs_i.h Fri Mar 17 07:10:10 2000
@@ -3,6 +3,9 @@

struct pipe_inode_info {
wait_queue_head_t wait;
+ void *umap;
+ int umap_length;
+ int umap_offset;
char *base;
unsigned int start;
unsigned int readers;
@@ -25,7 +28,6 @@
#define PIPE_WAITING_READERS(inode) ((inode).i_pipe->waiting_readers)
#define PIPE_WAITING_WRITERS(inode) ((inode).i_pipe->waiting_writers)

-#define PIPE_EMPTY(inode) (PIPE_LEN(inode) == 0)
#define PIPE_FULL(inode) (PIPE_LEN(inode) == PIPE_SIZE)
#define PIPE_FREE(inode) (PIPE_SIZE - PIPE_LEN(inode))
#define PIPE_END(inode) ((PIPE_START(inode) + PIPE_LEN(inode)) & (PIPE_SIZE-1))
--- fs/pipe.c.~1~ Tue Mar 7 17:41:52 2000
+++ fs/pipe.c Fri Mar 17 08:53:37 2000
@@ -8,6 +8,8 @@
#include <linux/file.h>
#include <linux/poll.h>
#include <linux/malloc.h>
+#include <linux/iobuf.h>
+#include <linux/highmem.h>
#include <linux/smp_lock.h>

#include <asm/uaccess.h>
@@ -31,6 +33,18 @@
* -- Julian Bradfield 1999-06-07.
*/

+#define PIPE_UMAP(inode) ((inode).i_pipe->umap)
+#define PIPE_UMAPOFF(inode) ((inode).i_pipe->umap_offset)
+#define PIPE_UMAPLEN(inode) ((inode).i_pipe->umap_length)
+
+#define PIPE_UMAP_EMPTY(inode) \
+ ((PIPE_UMAP(inode) == NULL) || \
+ (PIPE_UMAPOFF(inode) >= PIPE_UMAPLEN(inode)))
+
+#define PIPE_EMPTY(inode) \
+ ((PIPE_LEN(inode) == 0) && PIPE_UMAP_EMPTY(inode))
+
+
/* Drop the inode semaphore and wait for a pipe event, atomically */
static void pipe_wait(struct inode * inode)
{
@@ -45,6 +59,65 @@
}

static ssize_t
+pipe_copy_from_kiobuf(char *buf, size_t count, struct kiobuf *kio, int kio_offset)
+{
+ struct page **cur_page;
+ unsigned long cur_offset, remains_this_page;
+ char *cur_buf;
+ int kio_remains;
+
+ kio_remains = kio->length;
+ cur_page = kio->maplist;
+ cur_offset = kio->offset;
+ while (kio_offset > 0 && kio_remains > 0) {
+ remains_this_page = PAGE_SIZE - cur_offset;
+ if (kio_offset < remains_this_page) {
+ cur_offset += kio_offset;
+ kio_remains -= kio_offset;
+ break;
+ }
+ kio_offset -= remains_this_page;
+ kio_remains -= remains_this_page;
+ cur_offset = 0;
+ cur_page++;
+ }
+
+ cur_buf = buf;
+ while (1) {
+ unsigned long kvaddr;
+ int err;
+
+ remains_this_page = PAGE_SIZE - cur_offset;
+ if (remains_this_page > count)
+ remains_this_page = count;
+ if (remains_this_page > kio_remains)
+ remains_this_page = kio_remains;
+
+ kvaddr = kmap(*cur_page);
+ err = copy_to_user(cur_buf, (void *)(kvaddr + cur_offset),
+ remains_this_page);
+ kunmap(*cur_page);
+
+ if (err)
+ return -EFAULT;
+
+ cur_buf += remains_this_page;
+ count -= remains_this_page;
+ if (count <= 0)
+ break;
+
+ kio_remains -= remains_this_page;
+ if (kio_remains <= 0)
+ break;
+
+ cur_offset = 0;
+ cur_page++;
+ }
+
+ return cur_buf - buf;
+}
+
+static ssize_t
pipe_read(struct file *filp, char *buf, size_t count, loff_t *ppos)
{
struct inode *inode = filp->f_dentry->d_inode;
@@ -93,24 +166,39 @@

/* Read what data is available. */
ret = -EFAULT;
- while (count > 0 && (size = PIPE_LEN(*inode))) {
- char *pipebuf = PIPE_BASE(*inode) + PIPE_START(*inode);
- ssize_t chars = PIPE_MAX_RCHUNK(*inode);
-
- if (chars > count)
- chars = count;
- if (chars > size)
- chars = size;
+ if (PIPE_UMAP(*inode)) {
+ ssize_t chars;

- if (copy_to_user(buf, pipebuf, chars))
+ chars = pipe_copy_from_kiobuf(buf, count,
+ PIPE_UMAP(*inode),
+ PIPE_UMAPOFF(*inode));
+ if (chars < 0)
goto out;

read += chars;
- PIPE_START(*inode) += chars;
- PIPE_START(*inode) &= (PIPE_SIZE - 1);
- PIPE_LEN(*inode) -= chars;
count -= chars;
buf += chars;
+ PIPE_UMAPOFF(*inode) += chars;
+ } else {
+ while (count > 0 && (size = PIPE_LEN(*inode))) {
+ char *pipebuf = PIPE_BASE(*inode) + PIPE_START(*inode);
+ ssize_t chars = PIPE_MAX_RCHUNK(*inode);
+
+ if (chars > count)
+ chars = count;
+ if (chars > size)
+ chars = size;
+
+ if (copy_to_user(buf, pipebuf, chars))
+ goto out;
+
+ read += chars;
+ PIPE_START(*inode) += chars;
+ PIPE_START(*inode) &= (PIPE_SIZE - 1);
+ PIPE_LEN(*inode) -= chars;
+ count -= chars;
+ buf += chars;
+ }
}

/* Cache behaviour optimization */
@@ -189,11 +277,70 @@

/* Copy into available space. */
ret = -EFAULT;
- while (count > 0) {
+ if (count >= PAGE_SIZE &&
+ !(filp->f_flags & O_NONBLOCK) &&
+ !(PIPE_WAITING_WRITERS(*inode))) {
+ struct kiobuf *kio;
+ int err, do_sigpipe;;
+
+ /* Bulk, non-blocking, sole writer, use kio. */
+ err = alloc_kiovec(1, &kio);
+ if (err)
+ goto kio_abort;
+
+ do_sigpipe = 0;
+ PIPE_UMAP(*inode) = kio;
+ while (count > 0) {
+ unsigned long iosize = count;
+
+ if (iosize > KIO_MAX_ATOMIC_BYTES)
+ iosize = KIO_MAX_ATOMIC_BYTES;
+
+ /* Since we only use atomic sized transfers, the
+ * only possible error here is EFAULT.
+ */
+ err = map_user_kiobuf(WRITE, kio, (unsigned long)buf, iosize);
+ if (err)
+ break;
+
+ PIPE_UMAPOFF(*inode) = 0;
+ PIPE_UMAPLEN(*inode) = iosize;
+
+ do {
+ wake_up_interruptible_sync(PIPE_WAIT(*inode));
+ PIPE_WAITING_WRITERS(*inode)++;
+ pipe_wait(inode);
+ PIPE_WAITING_WRITERS(*inode)--;
+ if (signal_pending(current)) {
+ unmap_kiobuf(kio);
+ goto kio_break;
+ }
+ if (!PIPE_READERS(*inode)) {
+ unmap_kiobuf(kio);
+ do_sigpipe = 1;
+ goto kio_break;
+ }
+ } while (!PIPE_UMAP_EMPTY(*inode));
+
+ unmap_kiobuf(kio);
+ count -= iosize;
+ written += iosize;
+ buf += iosize;
+ }
+ kio_break:
+ free_kiovec(1, &kio);
+ PIPE_UMAP(*inode) = NULL;
+
+ if (do_sigpipe)
+ goto sigpipe;
+ } else while (count > 0) {
int space;
- char *pipebuf = PIPE_BASE(*inode) + PIPE_END(*inode);
- ssize_t chars = PIPE_MAX_WCHUNK(*inode);
+ char *pipebuf;
+ ssize_t chars;

+kio_abort:
+ pipebuf = PIPE_BASE(*inode) + PIPE_END(*inode);
+ chars = PIPE_MAX_WCHUNK(*inode);
if ((space = PIPE_FREE(*inode)) != 0) {
if (chars > count)
chars = count;
@@ -380,6 +527,8 @@
struct pipe_inode_info *info = inode->i_pipe;
inode->i_pipe = NULL;
free_page((unsigned long) info->base);
+ if (info->umap != NULL)
+ BUG();
kfree(info);
} else {
wake_up_interruptible(PIPE_WAIT(*inode));
@@ -543,6 +692,7 @@
PIPE_START(*inode) = PIPE_LEN(*inode) = 0;
PIPE_READERS(*inode) = PIPE_WRITERS(*inode) = 1;
PIPE_WAITING_READERS(*inode) = PIPE_WAITING_WRITERS(*inode) = 0;
+ PIPE_UMAP(*inode) = NULL;

/*
* Mark the inode dirty from the very beginning,
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/

\
 
 \ /
  Last update: 2005-03-22 13:57    [W:0.100 / U:0.428 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site