buffer.c 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. /*
  2. * QEMU generic buffers
  3. *
  4. * Copyright (c) 2015 Red Hat, Inc.
  5. *
  6. * This library is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 2.1 of the License, or (at your option) any later version.
  10. *
  11. * This library is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public
  17. * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  18. *
  19. */
  20. #include "qemu/osdep.h"
  21. #include "qemu/host-utils.h"
  22. #include "qemu/buffer.h"
  23. #include "trace.h"
  24. #define BUFFER_MIN_INIT_SIZE 4096
  25. #define BUFFER_MIN_SHRINK_SIZE 65536
  26. /* define the factor alpha for the exponential smoothing
  27. * that is used in the average size calculation. a shift
  28. * of 7 results in an alpha of 1/2^7. */
  29. #define BUFFER_AVG_SIZE_SHIFT 7
  30. static size_t buffer_req_size(Buffer *buffer, size_t len)
  31. {
  32. return MAX(BUFFER_MIN_INIT_SIZE,
  33. pow2ceil(buffer->offset + len));
  34. }
  35. static void buffer_adj_size(Buffer *buffer, size_t len)
  36. {
  37. size_t old = buffer->capacity;
  38. buffer->capacity = buffer_req_size(buffer, len);
  39. buffer->buffer = g_realloc(buffer->buffer, buffer->capacity);
  40. trace_buffer_resize(buffer->name ?: "unnamed",
  41. old, buffer->capacity);
  42. /* make it even harder for the buffer to shrink, reset average size
  43. * to current capacity if it is larger than the average. */
  44. buffer->avg_size = MAX(buffer->avg_size,
  45. buffer->capacity << BUFFER_AVG_SIZE_SHIFT);
  46. }
  47. void buffer_init(Buffer *buffer, const char *name, ...)
  48. {
  49. va_list ap;
  50. va_start(ap, name);
  51. buffer->name = g_strdup_vprintf(name, ap);
  52. va_end(ap);
  53. }
  54. static uint64_t buffer_get_avg_size(Buffer *buffer)
  55. {
  56. return buffer->avg_size >> BUFFER_AVG_SIZE_SHIFT;
  57. }
  58. void buffer_shrink(Buffer *buffer)
  59. {
  60. size_t new;
  61. /* Calculate the average size of the buffer as
  62. * avg_size = avg_size * ( 1 - a ) + required_size * a
  63. * where a is 1 / 2 ^ BUFFER_AVG_SIZE_SHIFT. */
  64. buffer->avg_size *= (1 << BUFFER_AVG_SIZE_SHIFT) - 1;
  65. buffer->avg_size >>= BUFFER_AVG_SIZE_SHIFT;
  66. buffer->avg_size += buffer_req_size(buffer, 0);
  67. /* And then only shrink if the average size of the buffer is much
  68. * too big, to avoid bumping up & down the buffers all the time.
  69. * realloc() isn't exactly cheap ... */
  70. new = buffer_req_size(buffer, buffer_get_avg_size(buffer));
  71. if (new < buffer->capacity >> 3 &&
  72. new >= BUFFER_MIN_SHRINK_SIZE) {
  73. buffer_adj_size(buffer, buffer_get_avg_size(buffer));
  74. }
  75. buffer_adj_size(buffer, 0);
  76. }
  77. void buffer_reserve(Buffer *buffer, size_t len)
  78. {
  79. if ((buffer->capacity - buffer->offset) < len) {
  80. buffer_adj_size(buffer, len);
  81. }
  82. }
  83. gboolean buffer_empty(Buffer *buffer)
  84. {
  85. return buffer->offset == 0;
  86. }
  87. uint8_t *buffer_end(Buffer *buffer)
  88. {
  89. return buffer->buffer + buffer->offset;
  90. }
  91. void buffer_reset(Buffer *buffer)
  92. {
  93. buffer->offset = 0;
  94. buffer_shrink(buffer);
  95. }
  96. void buffer_free(Buffer *buffer)
  97. {
  98. trace_buffer_free(buffer->name ?: "unnamed", buffer->capacity);
  99. g_free(buffer->buffer);
  100. g_free(buffer->name);
  101. buffer->offset = 0;
  102. buffer->capacity = 0;
  103. buffer->buffer = NULL;
  104. buffer->name = NULL;
  105. }
  106. void buffer_append(Buffer *buffer, const void *data, size_t len)
  107. {
  108. memcpy(buffer->buffer + buffer->offset, data, len);
  109. buffer->offset += len;
  110. }
  111. void buffer_advance(Buffer *buffer, size_t len)
  112. {
  113. memmove(buffer->buffer, buffer->buffer + len,
  114. (buffer->offset - len));
  115. buffer->offset -= len;
  116. buffer_shrink(buffer);
  117. }
  118. void buffer_move_empty(Buffer *to, Buffer *from)
  119. {
  120. trace_buffer_move_empty(to->name ?: "unnamed",
  121. from->offset,
  122. from->name ?: "unnamed");
  123. assert(to->offset == 0);
  124. g_free(to->buffer);
  125. to->offset = from->offset;
  126. to->capacity = from->capacity;
  127. to->buffer = from->buffer;
  128. from->offset = 0;
  129. from->capacity = 0;
  130. from->buffer = NULL;
  131. }
  132. void buffer_move(Buffer *to, Buffer *from)
  133. {
  134. if (to->offset == 0) {
  135. buffer_move_empty(to, from);
  136. return;
  137. }
  138. trace_buffer_move(to->name ?: "unnamed",
  139. from->offset,
  140. from->name ?: "unnamed");
  141. buffer_reserve(to, from->offset);
  142. buffer_append(to, from->buffer, from->offset);
  143. g_free(from->buffer);
  144. from->offset = 0;
  145. from->capacity = 0;
  146. from->buffer = NULL;
  147. }