qmalloc.c 12 KB

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