Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Модули на С. Инструменты и правила — разбираем ...

Модули на С. Инструменты и правила — разбираем на примере

Алексей Бузанов (Программист, Mail.Ru Group)

Avatar for Moscow Python Meetup

Moscow Python Meetup

September 12, 2013
Tweet

More Decks by Moscow Python Meetup

Other Decks in Programming

Transcript

  1. Moscow Django MeetUp №14 def is_palindrome(num): x = str(num) return

    x == x[::-1] def palindrome_factors(digits): max_num = (10 ** digits) - 1 min_num = max_num // 10 best = (0, 0, 0) for i in range(max_num, min_num, -1): for j in range(i, min_num, -1): multi = i * j if multi > best[0] and is_palindrome(multi): best = (multi, i, j) return best
  2. Moscow Django MeetUp №14 #include <Python.h> static int is_palindrome(int num,

    int digits) { int* check_array = malloc(digits * 2); int l = 0, i = 0; for (l = 0; num != 0; l++, num /= 10) { check_array[l] = num % 10; } for (i = 0; i < l/2; i++) { if (check_array[i] != check_array[l - i - 1]) { return 0; } } free(check_array); return 1; }
  3. Moscow Django MeetUp №14 static PyObject* cpal_palindrome_factors(PyObject* self, PyObject* args)

    { int digits; if (!PyArg_ParseTuple(args, "i", &digits)) { return NULL; } int max_num=0, min_num=0, i, j, multi, best[3] = {0, 0, 0}; max_num = pow(10, digits) - 1; min_num = max_num/10; for (i = max_num; i > min_num; i--) { for (j = i; j > min_num; j--) { multi = i * j; if (multi > best[0] && is_palindrome(multi, digits)) { best[0] = multi; best[1] = i; best[2] = j; } } } return Py_BuildValue("iii", best[0], best[1], best[2]); }
  4. Moscow Django MeetUp №14 static PyMethodDef cpal_methods[] = { {"palindrome_factors",

    (PyCFunction)cpal_palindrome_factors, METH_VARARGS, "calc max palindrome factors"}, {NULL, NULL, 0, NULL} }; void initcpal(void) { Py_InitModule("cpal", cpal_methods); }
  5. Moscow Django MeetUp №14 $ cat setup.py from distutils.core import

    setup, Extension setup(name='cpal', version='1.0', author = 'Alexey Buzanov', author_email = '[email protected]', ext_modules=[Extension('cpal', ['cpal.c'])]) $ python setup.py build ... $ python setup.py install ... $ python setup.py sdist ...
  6. Moscow Django MeetUp №14 $ time python run.py -d3 Answer:

    906609 = (993 x 913) real 0m0.092s $ time python run.py -d3 -c Answer: 906609 = (993 x 913) real 0m0.032s
  7. Moscow Django MeetUp №14 $ python run.py -d4 -c ***

    Error in `python': free(): invalid next size (fast): 0x0000000000f20510 *** ======= Backtrace: ========= /lib/x86_64-linux-gnu/libc.so.6(+0x80a46)[0x7f15a36a0a46] …/site-packages/cpal.so(+0x9d1)[0x7f15a1fe29d1] ...
  8. Moscow Django MeetUp №14 $ ./configure --without-pymalloc --prefix=/opt/python27_gdb $ make

    && make install $ virtualenv -p /opt/python27_gdb/bin/python gdb_env $ source gdb_env/bin/activate $ CFLAGS="-O0" python setup.py build -g -f $ python setup.py install
  9. Moscow Django MeetUp №14 $ gdb python (gdb) run run.py

    -d4 –c *** Error in `python': free(): invalid next size (fast): 0x000000000090dba0 *** (gdb) bt #4 _int_free … at malloc.c:3758 #5 0x00007ffff5aab9a8 in is_palindrome (num=0, digits=4) at cpal.c:16 #6 0x00007ffff5aabab7 in cpal_palindrome_factors (self=0x0, args=0x941b50) at cpal.c:39 (gdb) b cpal.c:16 (gdb) run Breakpoint 1, is_palindrome (num=0, digits=4) at cpal.c:16 16 free(check_array);
  10. Moscow Django MeetUp №14 (gdb) p digits $1 = 4

    (gdb) p check_array[0] $2 = 9 (gdb) p check_array[1] $3 = 9 (gdb) p &check_array[0] $4 = (int *) 0x90dba0 (gdb) p &check_array[1] $5 = (int *) 0x90dba4 (gdb) l 5 4 static int is_palindrome(int num, int digits) { 5 int* check_array = malloc(digits * 2); 6 int l = 0, i = 0;
  11. Moscow Django MeetUp №14 $ cat Misc/gdbinit >> ~/.gdbinit (gdb)

    b cpal.c:23 (gdb) run 23 if (!PyArg_ParseTuple(args, "i", &digits)) { (gdb) pyo args object : (4,) type : tuple refcount: 1 address : 0x941b50 $7 = void
  12. Moscow Django MeetUp №14 static int is_palindrome(int num, int digits)

    { int* check_array = malloc(digits * 2 * sizeof(int)); int l = 0, i = 0; for (l = 0; num != 0; l++, num /= 10) { check_array[l] = num % 10; } for (i = 0; i < l/2; i++) { if (check_array[i] != check_array[l - i - 1]) { return 0; } } free(check_array); return 1; }
  13. Moscow Django MeetUp №14 $ CFLAGS="-O0" python setup.py build -g

    -f && python setup.py install $ time python run.py -d4 –c Answer: 99000099 = (9999 x 9901) real 0m0.105s $ time python run.py -d4 Answer: 99000099 = (9999 x 9901) real 0m3.958s
  14. Moscow Django MeetUp №14 $ time python run.py -d5 -c

    Answer: 2147447412 = (99807 x 21516) real 0m8.641s $ time python run.py -d5 Answer: 9966006699 = (99979 x 99681) real 6m41.028s
  15. Moscow Django MeetUp №14 typedef unsigned PY_LONG_LONG pal_t; static int

    is_palindrome(pal_t num, int digits); static PyObject* cpal_palindrome_factors(PyObject* self, PyObject* args) { … pal_t max_num = 0, min_num = 0, i, j, multi; pal_t best[3] = {0, 0, 0}; … return Py_BuildValue("KKK", best[0], best[1], best[2]); }
  16. Moscow Django MeetUp №14 $ time python run.py -d5 -c

    Answer: 9966006699 = (99979 x 99681) real 0m9.003s
  17. Moscow Django MeetUp №14 $ valgrind --tool=memcheck --leak-check=full --show-possibly-lost=no python

    run.py -d4 -c Answer: 99000099 = (9999 x 9901) ... 79,968 bytes in 2,499 blocks are definitely lost in loss record 1,635 of 1,636 by 0x7B618CA: is_palindrome (cpal.c:8) by 0x7B61B55: cpal_palindrome_factors (cpal.c:46) by 0x4A1F7D: PyEval_EvalFrameEx (ceval.c:4021) ... LEAK SUMMARY: definitely lost: 79,968 bytes in 2,499 blocks possibly lost: 417,643 bytes in 2,380 blocks still reachable: 881,455 bytes in 6,097 blocks
  18. Moscow Django MeetUp №14 static int is_palindrome(pal_t num, int digits)

    { int* check_array = malloc(digits * 2 * sizeof(int)); int l = 0, i = 0; for (l = 0; num != 0; l++, num /= 10) { check_array[l] = num % 10; } for (i = 0; i < l/2; i++) { if (check_array[i] != check_array[l - i - 1]) { return 0; } } free(check_array); return 1; }
  19. Moscow Django MeetUp №14 static int is_palindrome(pal_t num, int digits)

    { int* check_array = malloc(digits * 2 * sizeof(int)); int l = 0, i = 0; for (l = 0; num != 0; l++, num /= 10) { check_array[l] = num % 10; } for (i = 0; i < l/2; i++) { if (check_array[i] != check_array[l - i - 1]) { free(check_array); return 0; } } free(check_array); return 1; }
  20. Moscow Django MeetUp №14 $ valgrind --tool=memcheck --leak-check=full --show-possibly-lost=no python

    run.py -d4 -c Answer: 99000099 = (9999 x 9901) ... LEAK SUMMARY: definitely lost: 0 bytes in 0 blocks possibly lost: 417,643 bytes in 2,380 blocks still reachable: 881,455 bytes in 6,097 blocks suppressed: 0 bytes in 0 blocks
  21. Moscow Django MeetUp №14 #include <Python.h> #include "pal.c" static PyObject*

    cpal_palindrome_factors(PyObject* self, PyObject* args) { int digits; if (!PyArg_ParseTuple(args, "i", &digits)) { return NULL; } pal_t best[3] = {0, 0, 0}; palindrome_factors(best, digits); return Py_BuildValue("KKK", best[0], best[1], best[2]); }
  22. Moscow Django MeetUp №14 $ cat main.c #include <stdlib.h> /*

    malloc, free */ #include <stdio.h> /* printf */ #include "pal.c" int main() { pal_t best[3] = {0, 0, 0}; palindrome_factors(best, 4); printf("Answer: %llu (%llu x %llu)\n", best[0], best[1], best[2]); return 0; } $ gcc main.c -g -O0 -lm -o pal.bin $ ./pal.bin Answer: 99000099 (9999 x 9901)
  23. Moscow Django MeetUp №14 $ valgrind --tool=massif --time-unit=B --threshold=0.001 --detailed-freq=1

    --stacks=yes ./pal.bin $ ms_print massif.out.25093 $ massif-visualizer massif.out.25093
  24. Moscow Django MeetUp №14 static int is_palindrome(pal_t num, int* check_array)

    … static void palindrome_factors(pal_t* best, int digits) { int* check_array = (int*)malloc(digits*2*sizeof(int)); ... if (multi > best[0] && is_palindrome(multi, check_array)) ... free(check_array); }
  25. Moscow Django MeetUp №14 $ time ./pal.bin Answer: 9966006699 real

    0m8.448s $ time ./pal.bin Answer: 9966006699 real 0m8.406s
  26. Moscow Django MeetUp №14 def palindrome_factors(digits): max_num = sum(9 *

    (10 ** i) for i in range(digits)) min_num = max_num // 10 best = (0, 0, 0) for i in xrange(max_num, min_num, -1): if i**2 <= best[0]: break for j in xrange(i, min_num, -1): multi = i * j if multi <= best[0]: break if is_palindrome(multi): best = (multi, i, j) return best
  27. Moscow Django MeetUp №14 $ time python run.py -d5 -c

    Answer: 9966006699 = (99979 x 99681) real 0m8.437s $ time python run.py -d5 Answer: 9966006699 = (99979 x 99681) real 0m3.731s