8 static PyObject *selftest(PyObject *self, PyObject *args)
10 if (!PyArg_ParseTuple(args, ""))
13 return Py_BuildValue("i", !bupsplit_selftest());
17 static PyObject *blobbits(PyObject *self, PyObject *args)
19 if (!PyArg_ParseTuple(args, ""))
21 return Py_BuildValue("i", BUP_BLOBBITS);
25 static PyObject *splitbuf(PyObject *self, PyObject *args)
27 unsigned char *buf = NULL;
28 int len = 0, out = 0, bits = -1;
30 if (!PyArg_ParseTuple(args, "t#", &buf, &len))
32 out = bupsplit_find_ofs(buf, len, &bits);
33 return Py_BuildValue("ii", out, bits);
37 static PyObject *bitmatch(PyObject *self, PyObject *args)
39 unsigned char *buf1 = NULL, *buf2 = NULL;
40 int len1 = 0, len2 = 0;
43 if (!PyArg_ParseTuple(args, "t#t#", &buf1, &len1, &buf2, &len2))
47 for (byte = 0; byte < len1 && byte < len2; byte++)
49 int b1 = buf1[byte], b2 = buf2[byte];
52 for (bit = 0; bit < 8; bit++)
53 if ( (b1 & (0x80 >> bit)) != (b2 & (0x80 >> bit)) )
59 return Py_BuildValue("i", byte*8 + bit);
63 static PyObject *firstword(PyObject *self, PyObject *args)
65 unsigned char *buf = NULL;
69 if (!PyArg_ParseTuple(args, "t#", &buf, &len))
75 v = ntohl(*(uint32_t *)buf);
76 return Py_BuildValue("I", v);
80 static PyObject *extract_bits(PyObject *self, PyObject *args)
82 unsigned char *buf = NULL;
83 int len = 0, nbits = 0;
86 if (!PyArg_ParseTuple(args, "t#i", &buf, &len, &nbits))
92 mask = (1<<nbits) - 1;
93 v = ntohl(*(uint32_t *)buf);
94 v = (v >> (32-nbits)) & mask;
95 return Py_BuildValue("I", v);
99 // I would have made this a lower-level function that just fills in a buffer
100 // with random values, and then written those values from python. But that's
101 // about 20% slower in my tests, and since we typically generate random
102 // numbers for benchmarking other parts of bup, any slowness in generating
103 // random bytes will make our benchmarks inaccurate. Plus nobody wants
104 // pseudorandom bytes much except for this anyway.
105 static PyObject *write_random(PyObject *self, PyObject *args)
107 uint32_t buf[1024/4];
108 int fd = -1, seed = 0;
110 long long len = 0, kbytes = 0, written = 0;
112 if (!PyArg_ParseTuple(args, "iLi", &fd, &len, &seed))
117 for (kbytes = 0; kbytes < len/1024; kbytes++)
120 for (i = 0; i < sizeof(buf)/sizeof(buf[0]); i++)
122 ret = write(fd, buf, sizeof(buf));
126 if (ret < (int)sizeof(buf))
128 if (kbytes/1024 > 0 && !(kbytes%1024))
129 fprintf(stderr, "Random: %lld Mbytes\r", kbytes/1024);
132 // handle non-multiples of 1024
136 for (i = 0; i < sizeof(buf)/sizeof(buf[0]); i++)
138 ret = write(fd, buf, len % 1024);
145 fprintf(stderr, "Random: %lld Mbytes, done.\n", kbytes/1024);
146 return Py_BuildValue("L", written);
150 static PyObject *open_noatime(PyObject *self, PyObject *args)
152 char *filename = NULL;
153 int attrs, attrs_noatime, fd;
154 if (!PyArg_ParseTuple(args, "s", &filename))
161 attrs |= O_LARGEFILE;
163 attrs_noatime = attrs;
165 attrs_noatime |= O_NOATIME;
167 fd = open(filename, attrs_noatime);
168 if (fd < 0 && errno == EPERM)
170 // older Linux kernels would return EPERM if you used O_NOATIME
171 // and weren't the file's owner. This pointless restriction was
172 // relaxed eventually, but we have to handle it anyway.
173 // (VERY old kernels didn't recognized O_NOATIME, but they would
174 // just harmlessly ignore it, so this branch won't trigger)
175 fd = open(filename, attrs);
178 return PyErr_SetFromErrnoWithFilename(PyExc_IOError, filename);
179 return Py_BuildValue("i", fd);
183 static PyObject *fadvise_done(PyObject *self, PyObject *args)
187 if (!PyArg_ParseTuple(args, "iL", &fd, &ofs))
189 #ifdef POSIX_FADV_DONTNEED
190 posix_fadvise(fd, 0, ofs, POSIX_FADV_DONTNEED);
192 return Py_BuildValue("");
196 static PyMethodDef faster_methods[] = {
197 { "selftest", selftest, METH_VARARGS,
198 "Check that the rolling checksum rolls correctly (for unit tests)." },
199 { "blobbits", blobbits, METH_VARARGS,
200 "Return the number of bits in the rolling checksum." },
201 { "splitbuf", splitbuf, METH_VARARGS,
202 "Split a list of strings based on a rolling checksum." },
203 { "bitmatch", bitmatch, METH_VARARGS,
204 "Count the number of matching prefix bits between two strings." },
205 { "firstword", firstword, METH_VARARGS,
206 "Return an int corresponding to the first 32 bits of buf." },
207 { "extract_bits", extract_bits, METH_VARARGS,
208 "Take the first 'nbits' bits from 'buf' and return them as an int." },
209 { "write_random", write_random, METH_VARARGS,
210 "Write random bytes to the given file descriptor" },
211 { "open_noatime", open_noatime, METH_VARARGS,
212 "open() the given filename for read with O_NOATIME if possible" },
213 { "fadvise_done", fadvise_done, METH_VARARGS,
214 "Inform the kernel that we're finished with earlier parts of a file" },
215 { NULL, NULL, 0, NULL }, // sentinel
218 PyMODINIT_FUNC init_helpers(void)
220 Py_InitModule("_helpers", faster_methods);