python api for resources

This commit is contained in:
Alexander 2017-09-18 01:41:39 +03:00
parent 53dde3b7f6
commit af3dcf84af
5 changed files with 219 additions and 27 deletions

View File

@ -305,9 +305,9 @@ class CoreResampleAlphaCorrectTest(PillowTestCase):
class CoreResamplePassesTest(PillowTestCase):
@contextmanager
def count(self, diff):
count = Image.core.getcount()
count = Image.core.get_stats()['new_count']
yield
self.assertEqual(Image.core.getcount() - count, diff)
self.assertEqual(Image.core.get_stats()['new_count'] - count, diff)
def test_horizontal(self):
im = hopper('L')

View File

@ -641,15 +641,6 @@ _new_block(PyObject* self, PyObject* args)
return PyImagingNew(ImagingNewBlock(mode, xsize, ysize));
}
static PyObject*
_getcount(PyObject* self, PyObject* args)
{
if (!PyArg_ParseTuple(args, ":getcount"))
return NULL;
return PyInt_FromLong(ImagingDefaultArena.stats_new_count);
}
static PyObject*
_linear_gradient(PyObject* self, PyObject* args)
{
@ -3337,6 +3328,169 @@ static PyTypeObject PixelAccess_Type = {
/* -------------------------------------------------------------------- */
static PyObject*
_get_stats(PyObject* self, PyObject* args)
{
PyObject* d;
ImagingMemoryArena arena = &ImagingDefaultArena;
if (!PyArg_ParseTuple(args, ":get_stats"))
return NULL;
d = PyDict_New();
if ( ! d)
return NULL;
PyDict_SetItemString(d, "new_count",
PyInt_FromLong(arena->stats_new_count));
PyDict_SetItemString(d, "allocated_blocks",
PyInt_FromLong(arena->stats_allocated_blocks));
PyDict_SetItemString(d, "reused_blocks",
PyInt_FromLong(arena->stats_reused_blocks));
PyDict_SetItemString(d, "reallocated_blocks",
PyInt_FromLong(arena->stats_reallocated_blocks));
PyDict_SetItemString(d, "freed_blocks",
PyInt_FromLong(arena->stats_freed_blocks));
return d;
}
static PyObject*
_reset_stats(PyObject* self, PyObject* args)
{
ImagingMemoryArena arena = &ImagingDefaultArena;
if (!PyArg_ParseTuple(args, ":reset_stats"))
return NULL;
arena->stats_new_count = 0;
arena->stats_allocated_blocks = 0;
arena->stats_reused_blocks = 0;
arena->stats_reallocated_blocks = 0;
arena->stats_freed_blocks = 0;
Py_INCREF(Py_None);
return Py_None;
}
static PyObject*
_get_alignment(PyObject* self, PyObject* args)
{
if (!PyArg_ParseTuple(args, ":get_alignment"))
return NULL;
return PyInt_FromLong(ImagingDefaultArena.alignment);
}
static PyObject*
_get_block_size(PyObject* self, PyObject* args)
{
if (!PyArg_ParseTuple(args, ":get_block_size"))
return NULL;
return PyInt_FromLong(ImagingDefaultArena.block_size);
}
static PyObject*
_get_blocks_max(PyObject* self, PyObject* args)
{
if (!PyArg_ParseTuple(args, ":get_blocks_max"))
return NULL;
return PyInt_FromLong(ImagingDefaultArena.blocks_max);
}
static PyObject*
_get_blocks_free(PyObject* self, PyObject* args)
{
if (!PyArg_ParseTuple(args, ":get_blocks_free"))
return NULL;
return PyInt_FromLong(ImagingDefaultArena.blocks_free);
}
static PyObject*
_set_alignment(PyObject* self, PyObject* args)
{
int alignment;
if (!PyArg_ParseTuple(args, "i:set_alignment", &alignment))
return NULL;
if (alignment < 1 || alignment > 128) {
PyErr_SetString(PyExc_ValueError, "alignment should be from 1 to 128");
return NULL;
}
/* Is power of two */
if (alignment & (alignment - 1)) {
PyErr_SetString(PyExc_ValueError, "alignment should be power of two");
return NULL;
}
ImagingDefaultArena.alignment = alignment;
Py_INCREF(Py_None);
return Py_None;
}
static PyObject*
_set_block_size(PyObject* self, PyObject* args)
{
int block_size;
if (!PyArg_ParseTuple(args, "i:set_block_size", &block_size))
return NULL;
if (block_size < 0) {
PyErr_SetString(PyExc_ValueError,
"block_size should be greater than 0");
return NULL;
}
if (block_size & 0xfff) {
PyErr_SetString(PyExc_ValueError,
"block_size should be multiple of 4096");
return NULL;
}
ImagingDefaultArena.block_size = block_size;
Py_INCREF(Py_None);
return Py_None;
}
static PyObject*
_set_blocks_max(PyObject* self, PyObject* args)
{
int blocks_max;
if (!PyArg_ParseTuple(args, "i:set_blocks_max", &blocks_max))
return NULL;
if (blocks_max < 0) {
PyErr_SetString(PyExc_ValueError,
"blocks_max should be greater than 0");
return NULL;
}
if ( ! ImagingMemorySetBlocksMax(&ImagingDefaultArena, blocks_max)) {
ImagingError_MemoryError();
return NULL;
}
Py_INCREF(Py_None);
return Py_None;
}
static PyObject*
_clear_cache(PyObject* self, PyObject* args)
{
if (!PyArg_ParseTuple(args, ":_clear_cache"))
return NULL;
ImagingMemoryClearCache(&ImagingDefaultArena);
Py_INCREF(Py_None);
return Py_None;
}
/* -------------------------------------------------------------------- */
/* FIXME: this is something of a mess. Should replace this with
pluggable codecs, but not before PIL 1.2 */
@ -3400,8 +3554,6 @@ static PyMethodDef functions[] = {
{"new", (PyCFunction)_new, 1},
{"merge", (PyCFunction)_merge, 1},
{"getcount", (PyCFunction)_getcount, 1},
/* Functions */
{"convert", (PyCFunction)_convert2, 1},
@ -3491,6 +3643,18 @@ static PyMethodDef functions[] = {
{"outline", (PyCFunction)PyOutline_Create, 1},
#endif
/* Resource management */
{"get_stats", (PyCFunction)_get_stats, 1},
{"reset_stats", (PyCFunction)_reset_stats, 1},
{"get_alignment", (PyCFunction)_get_alignment, 1},
{"get_block_size", (PyCFunction)_get_block_size, 1},
{"get_blocks_max", (PyCFunction)_get_blocks_max, 1},
{"get_blocks_free", (PyCFunction)_get_blocks_free, 1},
{"set_alignment", (PyCFunction)_set_alignment, 1},
{"set_block_size", (PyCFunction)_set_block_size, 1},
{"set_blocks_max", (PyCFunction)_set_blocks_max, 1},
{"clear_cache", (PyCFunction)_clear_cache, 1},
{NULL, NULL} /* sentinel */
};

View File

@ -52,3 +52,6 @@ identified the format of the clipboard data.
The ``PIL.Image.core.copy`` and ``PIL.Image.Image.im.copy2`` methods
have been removed.
The ``PIL.Image.core.getcount`` methods have been removed, use
``PIL.Image.core.get_stats()['new_count']`` property instead.

View File

@ -160,10 +160,10 @@ typedef struct ImagingMemoryArena {
int blocks_free;
void **blocks;
int stats_new_count;
int stats_allocated_block;
int stats_reused_block;
int stats_reallocated_block;
int stats_freed_block;
int stats_allocated_blocks;
int stats_reused_blocks;
int stats_reallocated_blocks;
int stats_freed_blocks;
} *ImagingMemoryArena;
@ -171,6 +171,8 @@ typedef struct ImagingMemoryArena {
/* ------- */
extern struct ImagingMemoryArena ImagingDefaultArena;
extern int ImagingMemorySetBlocksMax(ImagingMemoryArena arena, int blocks_max);
extern void ImagingMemoryClearCache(ImagingMemoryArena arena);
extern Imaging ImagingNew(const char* mode, int xsize, int ysize);
extern Imaging ImagingNewDirty(const char* mode, int xsize, int ysize);

View File

@ -273,24 +273,47 @@ struct ImagingMemoryArena ImagingDefaultArena = {
0, 0, 0, 0, 0 // Stats
};
void
memory_set_blocks_max(ImagingMemoryArena arena, int blocks_max)
int
ImagingMemorySetBlocksMax(ImagingMemoryArena arena, int blocks_max)
{
void *p;
/* Free already cached blocks */
while (arena->blocks_free > blocks_max) {
arena->blocks_free -= 1;
free(arena->blocks[arena->blocks_free]);
arena->stats_freed_block += 1;
arena->stats_freed_blocks += 1;
}
arena->blocks_max = blocks_max;
if (blocks_max == 0 && arena->blocks != NULL) {
free(arena->blocks);
arena->blocks = NULL;
} else if (arena->blocks != NULL) {
arena->blocks = realloc(arena->blocks, sizeof(void*) * blocks_max);
p = realloc(arena->blocks, sizeof(void*) * blocks_max);
if ( ! p) {
// Leave previous blocks_max value
return 0;
}
arena->blocks = p;
} else {
arena->blocks = calloc(sizeof(void*), blocks_max);
if ( ! arena->blocks) {
// Fallback to 0
arena->blocks_max = 0;
return 0;
}
}
arena->blocks_max = blocks_max;
return 1;
}
void
ImagingMemoryClearCache(ImagingMemoryArena arena)
{
while (arena->blocks_free > 0) {
arena->blocks_free -= 1;
free(arena->blocks[arena->blocks_free]);
arena->stats_freed_blocks += 1;
}
}
@ -303,12 +326,12 @@ memory_get_block(ImagingMemoryArena arena, int requested_size, int dirty)
block = realloc(arena->blocks[arena->blocks_free], requested_size);
if ( ! block) {
free(arena->blocks[arena->blocks_free]);
arena->stats_freed_block += 1;
arena->stats_freed_blocks += 1;
return NULL;
}
arena->stats_reused_block += 1;
arena->stats_reused_blocks += 1;
if (block != arena->blocks[arena->blocks_free]) {
arena->stats_reallocated_block += 1;
arena->stats_reallocated_blocks += 1;
}
if ( ! dirty) {
memset(block, 0, requested_size);
@ -319,7 +342,7 @@ memory_get_block(ImagingMemoryArena arena, int requested_size, int dirty)
} else {
block = calloc(1, requested_size);
}
arena->stats_allocated_block += 1;
arena->stats_allocated_blocks += 1;
}
return block;
}
@ -332,7 +355,7 @@ memory_return_block(ImagingMemoryArena arena, void *block)
arena->blocks_free += 1;
} else {
free(block);
arena->stats_freed_block += 1;
arena->stats_freed_blocks += 1;
}
}