qmalloc.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. /*
  10. * malloc
  11. *
  12. * Uses Quickfit (see SIGPLAN Notices October 1988)
  13. * with allocator from Kernighan & Ritchie
  14. *
  15. * This is a placeholder.
  16. */
  17. #include "u.h"
  18. #include "../port/lib.h"
  19. #include "mem.h"
  20. #include "dat.h"
  21. #include "fns.h"
  22. #include <pool.h>
  23. typedef double Align;
  24. typedef union Header Header;
  25. typedef struct Qlist Qlist;
  26. union Header {
  27. struct {
  28. Header *next;
  29. u32 size;
  30. } s;
  31. Align al;
  32. };
  33. struct Qlist {
  34. Lock lk;
  35. Header *first;
  36. u32 nalloc;
  37. };
  38. enum {
  39. Unitsz = sizeof(Header), /* 16 bytes on amd64 */
  40. };
  41. #define NUNITS(n) (HOWMANY(n, Unitsz) + 1)
  42. #define NQUICK ((512 / Unitsz) + 1) /* 33 on amd64 */
  43. static Qlist quicklist[NQUICK + 1];
  44. static Header misclist;
  45. static Header *rover;
  46. static unsigned tailsize;
  47. static unsigned tailnunits;
  48. static Header *tailbase;
  49. static Header *tailptr;
  50. static Header checkval;
  51. static int morecore(unsigned);
  52. enum {
  53. QSmalign = 0,
  54. QSmalignquick,
  55. QSmalignrover,
  56. QSmalignfront,
  57. QSmalignback,
  58. QSmaligntail,
  59. QSmalignnottail,
  60. QSmalloc,
  61. QSmallocrover,
  62. QSmalloctail,
  63. QSfree,
  64. QSfreetail,
  65. QSfreequick,
  66. QSfreenext,
  67. QSfreeprev,
  68. QSmax
  69. };
  70. static void qfreeinternal(void *);
  71. static int qstats[QSmax];
  72. static char *qstatstr[QSmax] = {
  73. [QSmalign] = "malign",
  74. [QSmalignquick] = "malignquick",
  75. [QSmalignrover] = "malignrover",
  76. [QSmalignfront] = "malignfront",
  77. [QSmalignback] = "malignback",
  78. [QSmaligntail] = "maligntail",
  79. [QSmalignnottail] = "malignnottail",
  80. [QSmalloc] = "malloc",
  81. [QSmallocrover] = "mallocrover",
  82. [QSmalloctail] = "malloctail",
  83. [QSfree] = "free",
  84. [QSfreetail] = "freetail",
  85. [QSfreequick] = "freequick",
  86. [QSfreenext] = "freenext",
  87. [QSfreeprev] = "freeprev",
  88. };
  89. static Lock mainlock;
  90. #define MLOCK ilock(&mainlock)
  91. #define MUNLOCK iunlock(&mainlock)
  92. #define QLOCK(l) ilock(l)
  93. #define QUNLOCK(l) iunlock(l)
  94. #define tailalloc(p, n) ((p) = tailptr, tailsize -= (n), tailptr += (n), \
  95. (p)->s.size = (n), (p)->s.next = &checkval)
  96. #define ISPOWEROF2(x) (/*((x) != 0) && */ !((x) & ((x)-1)))
  97. #define ALIGNHDR(h, a) (Header *)((((usize)(h)) + ((a)-1)) & ~((a)-1))
  98. /*
  99. * From libc malloc.c to *draw devices
  100. */
  101. typedef struct Private Private;
  102. struct Private {
  103. Lock lk;
  104. char *end;
  105. char msg[256]; /* a rock for messages to be printed at unlock */
  106. };
  107. /*
  108. * Experiment: per-core quick lists.
  109. * change quicklist to be
  110. * static Qlist quicklist[MACHMAX][NQUICK+1];
  111. * and define QLIST to be quicklist[machp()->machno]
  112. *
  113. * using quicklist[machp()->machno] runs out of memory soon.
  114. * using quicklist[machp()->machno%4] yields times worse than using quicklist!
  115. */
  116. #define QLIST quicklist
  117. static void *
  118. qmallocalign(usize nbytes, usize align, i32 offset, usize span)
  119. {
  120. Qlist *qlist;
  121. usize aligned;
  122. Header **pp, *p, *q, *r;
  123. u32 naligned, nunits, n;
  124. if(nbytes == 0 || offset != 0 || span != 0)
  125. return nil;
  126. if(!ISPOWEROF2(align) || align < sizeof(Header))
  127. return nil;
  128. qstats[QSmalign]++;
  129. nunits = NUNITS(nbytes);
  130. if(nunits <= NQUICK){
  131. /*
  132. * Look for a conveniently aligned block
  133. * on one of the quicklists.
  134. */
  135. qlist = &QLIST[nunits];
  136. QLOCK(&qlist->lk);
  137. pp = &qlist->first;
  138. for(p = *pp; p != nil; p = p->s.next){
  139. if(ALIGNED(p + 1, align)){
  140. *pp = p->s.next;
  141. p->s.next = &checkval;
  142. QUNLOCK(&qlist->lk);
  143. qstats[QSmalignquick]++;
  144. return p + 1;
  145. }
  146. pp = &p->s.next;
  147. }
  148. QUNLOCK(&qlist->lk);
  149. }
  150. MLOCK;
  151. if(nunits > tailsize){
  152. /* hard way */
  153. if((q = rover) != nil){
  154. do {
  155. p = q->s.next;
  156. if(p->s.size < nunits)
  157. continue;
  158. aligned = ALIGNED(p + 1, align);
  159. naligned = NUNITS(align) - 1;
  160. if(!aligned && p->s.size < nunits + naligned)
  161. continue;
  162. /*
  163. * This block is big enough, remove it
  164. * from the list.
  165. */
  166. q->s.next = p->s.next;
  167. rover = q;
  168. qstats[QSmalignrover]++;
  169. /*
  170. * Free any runt in front of the alignment.
  171. */
  172. if(!aligned){
  173. r = p;
  174. p = ALIGNHDR(p + 1, align) - 1;
  175. n = p - r;
  176. p->s.size = r->s.size - n;
  177. r->s.size = n;
  178. r->s.next = &checkval;
  179. qfreeinternal(r + 1);
  180. qstats[QSmalignfront]++;
  181. }
  182. /*
  183. * Free any residue after the aligned block.
  184. */
  185. if(p->s.size > nunits){
  186. r = p + nunits;
  187. r->s.size = p->s.size - nunits;
  188. r->s.next = &checkval;
  189. qstats[QSmalignback]++;
  190. qfreeinternal(r + 1);
  191. p->s.size = nunits;
  192. }
  193. p->s.next = &checkval;
  194. MUNLOCK;
  195. return p + 1;
  196. } while((q = p) != rover);
  197. }
  198. if((n = morecore(nunits)) == 0){
  199. MUNLOCK;
  200. return nil;
  201. }
  202. tailsize += n;
  203. }
  204. q = ALIGNHDR(tailptr + 1, align);
  205. if(q == tailptr + 1){
  206. tailalloc(p, nunits);
  207. qstats[QSmaligntail]++;
  208. } else {
  209. naligned = NUNITS(align) - 1;
  210. if(tailsize < nunits + naligned){
  211. /*
  212. * There are at least nunits,
  213. * get enough for alignment.
  214. */
  215. if((n = morecore(naligned)) == 0){
  216. MUNLOCK;
  217. return nil;
  218. }
  219. tailsize += n;
  220. }
  221. /*
  222. * Save the residue before the aligned allocation
  223. * and free it after the tail pointer has been bumped
  224. * for the main allocation.
  225. */
  226. n = q - tailptr - 1;
  227. tailalloc(r, n);
  228. tailalloc(p, nunits);
  229. qstats[QSmalignnottail]++;
  230. qfreeinternal(r + 1);
  231. }
  232. MUNLOCK;
  233. return p + 1;
  234. }
  235. static void *
  236. qmalloc(usize nbytes)
  237. {
  238. Qlist *qlist;
  239. Header *p, *q;
  240. u32 nunits, n;
  241. ///* FIXME: (ignore for now)
  242. if(nbytes == 0)
  243. return nil;
  244. //*/
  245. qstats[QSmalloc]++;
  246. nunits = NUNITS(nbytes);
  247. if(nunits <= NQUICK){
  248. qlist = &QLIST[nunits];
  249. QLOCK(&qlist->lk);
  250. if((p = qlist->first) != nil){
  251. qlist->first = p->s.next;
  252. qlist->nalloc++;
  253. QUNLOCK(&qlist->lk);
  254. p->s.next = &checkval;
  255. return p + 1;
  256. }
  257. QUNLOCK(&qlist->lk);
  258. }
  259. MLOCK;
  260. if(nunits > tailsize){
  261. /* hard way */
  262. if((q = rover) != nil){
  263. do {
  264. p = q->s.next;
  265. if(p->s.size >= nunits){
  266. if(p->s.size > nunits){
  267. p->s.size -= nunits;
  268. p += p->s.size;
  269. p->s.size = nunits;
  270. } else
  271. q->s.next = p->s.next;
  272. p->s.next = &checkval;
  273. rover = q;
  274. qstats[QSmallocrover]++;
  275. MUNLOCK;
  276. return p + 1;
  277. }
  278. } while((q = p) != rover);
  279. }
  280. if((n = morecore(nunits)) == 0){
  281. MUNLOCK;
  282. return nil;
  283. }
  284. tailsize += n;
  285. }
  286. qstats[QSmalloctail]++;
  287. tailalloc(p, nunits);
  288. MUNLOCK;
  289. return p + 1;
  290. }
  291. static void
  292. qfreeinternal(void *ap)
  293. {
  294. Qlist *qlist;
  295. Header *p, *q;
  296. u32 nunits;
  297. if(ap == nil)
  298. return;
  299. qstats[QSfree]++;
  300. p = (Header *)ap - 1;
  301. if((nunits = p->s.size) == 0 || p->s.next != &checkval)
  302. panic("malloc: corrupt allocation arena\n");
  303. if(tailptr != nil && p + nunits == tailptr){
  304. /* block before tail */
  305. tailptr = p;
  306. tailsize += nunits;
  307. qstats[QSfreetail]++;
  308. return;
  309. }
  310. if(nunits <= NQUICK){
  311. qlist = &QLIST[nunits];
  312. QLOCK(&qlist->lk);
  313. p->s.next = qlist->first;
  314. qlist->first = p;
  315. QUNLOCK(&qlist->lk);
  316. qstats[QSfreequick]++;
  317. return;
  318. }
  319. if((q = rover) == nil){
  320. q = &misclist;
  321. q->s.size = 0;
  322. q->s.next = q;
  323. }
  324. for(; !(p > q && p < q->s.next); q = q->s.next)
  325. if(q >= q->s.next && (p > q || p < q->s.next))
  326. break;
  327. if(p + p->s.size == q->s.next){
  328. p->s.size += q->s.next->s.size;
  329. p->s.next = q->s.next->s.next;
  330. qstats[QSfreenext]++;
  331. } else
  332. p->s.next = q->s.next;
  333. if(q + q->s.size == p){
  334. q->s.size += p->s.size;
  335. q->s.next = p->s.next;
  336. qstats[QSfreeprev]++;
  337. } else
  338. q->s.next = p;
  339. rover = q;
  340. }
  341. u32
  342. msize(void *ap)
  343. {
  344. Header *p;
  345. u32 nunits;
  346. if(ap == nil)
  347. return 0;
  348. p = (Header *)ap - 1;
  349. if((nunits = p->s.size) == 0 || p->s.next != &checkval)
  350. panic("malloc: corrupt allocation arena\n");
  351. return (nunits - 1) * sizeof(Header);
  352. }
  353. static void
  354. mallocreadfmt(char *s, char *e)
  355. {
  356. char *p;
  357. Header *q;
  358. int i, n, t;
  359. Qlist *qlist;
  360. p = seprint(s, e,
  361. "%llu memory\n"
  362. "%d pagesize\n"
  363. "%llu kernel\n",
  364. (u64)conf.npage * PGSZ,
  365. PGSZ,
  366. (u64)conf.npage - conf.upages);
  367. t = 0;
  368. for(i = 0; i <= NQUICK; i++){
  369. n = 0;
  370. qlist = &QLIST[i];
  371. QLOCK(&qlist->lk);
  372. for(q = qlist->first; q != nil; q = q->s.next){
  373. // if(q->s.size != i)
  374. // p = seprint(p, e, "q%d\t%#p\t%u\n",
  375. // i, q, q->s.size);
  376. n++;
  377. }
  378. QUNLOCK(&qlist->lk);
  379. // if(n != 0)
  380. // p = seprint(p, e, "q%d %d\n", i, n);
  381. t += n * i * sizeof(Header);
  382. }
  383. p = seprint(p, e, "quick: %u bytes total\n", t);
  384. MLOCK;
  385. if((q = rover) != nil){
  386. i = t = 0;
  387. do {
  388. t += q->s.size;
  389. i++;
  390. // p = seprint(p, e, "m%d\t%#p\n", q->s.size, q);
  391. } while((q = q->s.next) != rover);
  392. p = seprint(p, e, "rover: %d blocks %u bytes total\n",
  393. i, t * sizeof(Header));
  394. }
  395. p = seprint(p, e, "total allocated %lu, %u remaining\n",
  396. (tailptr - tailbase) * sizeof(Header), tailnunits * sizeof(Header));
  397. for(i = 0; i < nelem(qstats); i++){
  398. if(qstats[i] == 0)
  399. continue;
  400. p = seprint(p, e, "%s %u\n", qstatstr[i], qstats[i]);
  401. }
  402. MUNLOCK;
  403. }
  404. i32
  405. mallocreadsummary(Chan *c, void *a, i32 n, i32 offset)
  406. {
  407. char *alloc;
  408. alloc = malloc(16 * READSTR);
  409. mallocreadfmt(alloc, alloc + 16 * READSTR);
  410. n = readstr(offset, a, n, alloc);
  411. free(alloc);
  412. return n;
  413. }
  414. void
  415. mallocsummary(void)
  416. {
  417. Header *q;
  418. int i, n, t;
  419. Qlist *qlist;
  420. t = 0;
  421. for(i = 0; i <= NQUICK; i++){
  422. n = 0;
  423. qlist = &QLIST[i];
  424. QLOCK(&qlist->lk);
  425. for(q = qlist->first; q != nil; q = q->s.next){
  426. if(q->s.size != i)
  427. DBG("q%d\t%#p\t%u\n", i, q, q->s.size);
  428. n++;
  429. }
  430. QUNLOCK(&qlist->lk);
  431. t += n * i * sizeof(Header);
  432. }
  433. print("quick: %u bytes total\n", t);
  434. MLOCK;
  435. if((q = rover) != nil){
  436. i = t = 0;
  437. do {
  438. t += q->s.size;
  439. i++;
  440. } while((q = q->s.next) != rover);
  441. }
  442. MUNLOCK;
  443. if(i != 0){
  444. print("rover: %d blocks %u bytes total\n",
  445. i, t * sizeof(Header));
  446. }
  447. print("total allocated %lu, %u remaining\n",
  448. (tailptr - tailbase) * sizeof(Header), tailnunits * sizeof(Header));
  449. for(i = 0; i < nelem(qstats); i++){
  450. if(qstats[i] == 0)
  451. continue;
  452. print("%s %u\n", qstatstr[i], qstats[i]);
  453. }
  454. }
  455. void
  456. free(void *ap)
  457. {
  458. MLOCK;
  459. qfreeinternal(ap);
  460. MUNLOCK;
  461. }
  462. void *
  463. malloc(u32 size)
  464. {
  465. void *v;
  466. if((v = qmalloc(size)) != nil)
  467. memset(v, 0, size);
  468. return v;
  469. }
  470. void *
  471. mallocz(u32 size, int clr)
  472. {
  473. void *v;
  474. if((v = malloc(size)) != nil && clr)
  475. memset(v, 0, size);
  476. return v;
  477. }
  478. void *
  479. mallocalign(u32 nbytes, u32 align, i32 offset, u32 span)
  480. {
  481. void *v;
  482. /*
  483. * Should this memset or should it be left to the caller?
  484. */
  485. if((v = qmallocalign(nbytes, align, offset, span)) != nil)
  486. memset(v, 0, nbytes);
  487. return v;
  488. }
  489. void *
  490. smalloc(u32 size)
  491. {
  492. Proc *up = externup();
  493. void *v;
  494. while((v = mallocz(size, 1)) == nil)
  495. tsleep(&up->sleep, return0, 0, 100);
  496. return v;
  497. }
  498. void *
  499. realloc(void *ap, u32 size)
  500. {
  501. void *v;
  502. Header *p;
  503. u32 osize;
  504. u32 nunits, ounits;
  505. /*
  506. * Easy stuff:
  507. * free and return nil if size is 0
  508. * (implementation-defined behaviour);
  509. * behave like malloc if ap is nil;
  510. * check for arena corruption;
  511. * do nothing if units are the same.
  512. */
  513. if(size == 0){
  514. MLOCK;
  515. qfreeinternal(ap);
  516. MUNLOCK;
  517. return nil;
  518. }
  519. if(ap == nil)
  520. return qmalloc(size);
  521. p = (Header *)ap - 1;
  522. if((ounits = p->s.size) == 0 || p->s.next != &checkval)
  523. panic("realloc: corrupt allocation arena\n");
  524. if((nunits = NUNITS(size)) <= ounits)
  525. return ap;
  526. /*
  527. * Slightly harder:
  528. * if this allocation abuts the tail, try to just
  529. * adjust the tailptr.
  530. */
  531. MLOCK;
  532. if(tailptr != nil && p + ounits == tailptr){
  533. if(ounits > nunits){
  534. p->s.size = nunits;
  535. tailsize += ounits - nunits;
  536. MUNLOCK;
  537. return ap;
  538. }
  539. if(tailsize >= nunits - ounits){
  540. p->s.size = nunits;
  541. tailsize -= nunits - ounits;
  542. MUNLOCK;
  543. return ap;
  544. }
  545. }
  546. MUNLOCK;
  547. /*
  548. * Worth doing if it's a small reduction?
  549. * Do it anyway if <= NQUICK?
  550. if((ounits-nunits) < 2)
  551. return ap;
  552. */
  553. /*
  554. * Too hard (or can't be bothered):
  555. * allocate, copy and free.
  556. * What does the standard say for failure here?
  557. */
  558. if((v = qmalloc(size)) != nil){
  559. osize = (ounits - 1) * sizeof(Header);
  560. if(size < osize)
  561. osize = size;
  562. memmove(v, ap, osize);
  563. MLOCK;
  564. qfreeinternal(ap);
  565. MUNLOCK;
  566. }
  567. return v;
  568. }
  569. void
  570. setmalloctag(void *v, u32 i)
  571. {
  572. }
  573. void
  574. mallocinit(void)
  575. {
  576. static alignas(2 * MiB) unsigned char kheap[256 * MiB];
  577. if(tailptr != nil)
  578. return;
  579. tailbase = (Header *)kheap;
  580. tailptr = tailbase;
  581. tailnunits = NUNITS(sizeof(kheap));
  582. print("base %#p ptr %#p nunits %u\n", tailbase, tailptr, tailnunits);
  583. }
  584. static int
  585. morecore(u32 nunits)
  586. {
  587. /*
  588. * First (simple) cut.
  589. * Pump it up when you don't really need it.
  590. * Pump it up until you can feel it.
  591. */
  592. if(nunits < NUNITS(128 * KiB))
  593. nunits = NUNITS(128 * KiB);
  594. if(nunits > tailnunits)
  595. nunits = tailnunits;
  596. tailnunits -= nunits;
  597. return nunits;
  598. }