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

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

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

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

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