Kernel: Remove the kmalloc_eternal heap :^)

This was a premature optimization from the early days of SerenityOS.
The eternal heap was a simple bump pointer allocator over a static
byte array. My original idea was to avoid heap fragmentation and improve
data locality, but both ideas were rooted in cargo culting, not data.

We would reserve 4 MiB at boot and only ended up using ~256 KiB, wasting
the rest.

This patch replaces all kmalloc_eternal() usage by regular kmalloc().
This commit is contained in:
Andreas Kling 2021-12-28 19:12:22 +01:00
parent a1be135891
commit ac7ce12123
Notes: sideshowbarker 2024-07-17 22:02:59 +09:00
46 changed files with 5 additions and 82 deletions

View File

@ -38,17 +38,6 @@ inline size_t malloc_good_size(size_t size) { return size; }
# endif
#endif
#ifdef KERNEL
# define AK_MAKE_ETERNAL \
public: \
void* operator new(size_t size) { return kmalloc_eternal(size); } \
void operator delete(void*, size_t) { VERIFY_NOT_REACHED(); } \
\
private:
#else
# define AK_MAKE_ETERNAL
#endif
using std::nothrow;
inline void* kmalloc_array(Checked<size_t> a, Checked<size_t> b)

View File

@ -13,7 +13,6 @@
namespace Kernel::USB {
class USBManagement {
AK_MAKE_ETERNAL;
public:
USBManagement();

View File

@ -42,7 +42,6 @@ enum class AHCIResetMode {
};
class CommandLine {
AK_MAKE_ETERNAL;
public:
static void early_initialize(const char* cmd_line);

View File

@ -13,7 +13,6 @@
namespace Kernel {
class ConsoleDevice final : public CharacterDevice {
AK_MAKE_ETERNAL
friend class DeviceManagement;
public:

View File

@ -24,7 +24,6 @@
namespace Kernel {
class DeviceManagement {
AK_MAKE_ETERNAL;
public:
DeviceManagement();

View File

@ -11,7 +11,6 @@
namespace Kernel {
class FullDevice final : public CharacterDevice {
AK_MAKE_ETERNAL
friend class DeviceManagement;
public:

View File

@ -31,7 +31,6 @@ class KeyboardClient;
class HIDManagement {
friend class KeyboardDevice;
friend class MouseDevice;
AK_MAKE_ETERNAL;
public:
HIDManagement();

View File

@ -11,7 +11,6 @@
namespace Kernel {
class KCOVDevice final : public BlockDevice {
AK_MAKE_ETERNAL
friend class DeviceManagement;
public:

View File

@ -13,7 +13,6 @@
namespace Kernel {
class MemoryDevice final : public CharacterDevice {
AK_MAKE_ETERNAL
friend class DeviceManagement;
public:

View File

@ -11,7 +11,6 @@
namespace Kernel {
class NullDevice final : public CharacterDevice {
AK_MAKE_ETERNAL
friend class DeviceManagement;
public:

View File

@ -30,7 +30,7 @@ UNMAP_AFTER_INIT void PCISerialDevice::detect()
// If this is the first port of the first pci serial device, store it as the debug PCI serial port (TODO: Make this configurable somehow?)
if (!is_available())
s_the = serial_device;
// NOTE: We intentionally leak the reference to serial_device here, as it is eternal
// NOTE: We intentionally leak the reference to serial_device here.
}
dmesgln("PCISerialDevice: Found {} @ {}", board_definition.name, device_identifier.address());

View File

@ -14,7 +14,6 @@
namespace Kernel {
class PCISerialDevice {
AK_MAKE_ETERNAL
public:
static void detect();
static SerialDevice& the();

View File

@ -11,7 +11,6 @@
namespace Kernel {
class RandomDevice final : public CharacterDevice {
AK_MAKE_ETERNAL
friend class DeviceManagement;
public:

View File

@ -12,7 +12,6 @@
namespace Kernel {
class SerialDevice final : public CharacterDevice {
AK_MAKE_ETERNAL
friend class DeviceManagement;
public:

View File

@ -39,7 +39,6 @@ struct VMWareCommand {
};
class VMWareBackdoor {
AK_MAKE_ETERNAL;
public:
VMWareBackdoor();

View File

@ -11,7 +11,6 @@
namespace Kernel {
class ZeroDevice final : public CharacterDevice {
AK_MAKE_ETERNAL
friend class DeviceManagement;
public:

View File

@ -33,7 +33,6 @@ struct UidAndGid {
};
class VirtualFileSystem {
AK_MAKE_ETERNAL
public:
// Required to be at least 8 by POSIX
// https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/limits.h.html

View File

@ -403,7 +403,6 @@ private:
JsonObjectSerializer<KBufferBuilder> json { builder };
json.add("kmalloc_allocated", stats.bytes_allocated);
json.add("kmalloc_available", stats.bytes_free);
json.add("kmalloc_eternal_allocated", stats.bytes_eternal);
json.add("user_physical_allocated", system_memory.user_physical_pages_used);
json.add("user_physical_available", system_memory.user_physical_pages - system_memory.user_physical_pages_used);
json.add("user_physical_committed", system_memory.user_physical_pages_committed);

View File

@ -21,7 +21,6 @@ struct BochsDisplayMMIORegisters;
class BochsGraphicsAdapter final : public GenericGraphicsAdapter
, public PCI::Device {
AK_MAKE_ETERNAL
friend class GraphicsManagement;
private:

View File

@ -17,7 +17,6 @@
namespace Kernel {
class FramebufferDevice final : public GenericFramebufferDevice {
AK_MAKE_ETERNAL
friend class DeviceManagement;
public:

View File

@ -16,7 +16,6 @@
namespace Kernel {
class GenericFramebufferDevice : public BlockDevice {
AK_MAKE_ETERNAL
friend class DeviceManagement;
public:

View File

@ -27,7 +27,6 @@ class GraphicsManagement {
friend class IntelNativeGraphicsAdapter;
friend class VGACompatibleAdapter;
friend class Graphics::VirtIOGPU::GraphicsAdapter;
AK_MAKE_ETERNAL
public:
static GraphicsManagement& the();

View File

@ -47,7 +47,6 @@ enum RegisterIndex {
class IntelNativeGraphicsAdapter final
: public VGACompatibleAdapter {
AK_MAKE_ETERNAL
public:
struct PLLSettings {
bool is_valid() const { return (n != 0 && m1 != 0 && m2 != 0 && p1 != 0 && p2 != 0); }

View File

@ -17,7 +17,6 @@ namespace Kernel {
class VGACompatibleAdapter : public GenericGraphicsAdapter
, public PCI::Device {
AK_MAKE_ETERNAL
public:
static NonnullRefPtr<VGACompatibleAdapter> initialize_with_preset_resolution(PCI::DeviceIdentifier const&, PhysicalAddress, size_t framebuffer_width, size_t framebuffer_height, size_t framebuffer_pitch);
static NonnullRefPtr<VGACompatibleAdapter> initialize(PCI::DeviceIdentifier const&);

View File

@ -35,7 +35,6 @@ class FramebufferDevice;
class GraphicsAdapter final
: public GenericGraphicsAdapter
, public VirtIO::Device {
AK_MAKE_ETERNAL
friend class FramebufferDevice;
public:

View File

@ -29,7 +29,6 @@ static constexpr size_t CHUNK_SIZE = 64;
#endif
#define POOL_SIZE (2 * MiB)
#define ETERNAL_RANGE_SIZE (4 * MiB)
namespace std {
const nothrow_t nothrow;
@ -307,18 +306,13 @@ READONLY_AFTER_INIT static KmallocGlobalData* g_kmalloc_global;
alignas(KmallocGlobalData) static u8 g_kmalloc_global_heap[sizeof(KmallocGlobalData)];
// Treat the heap as logically separate from .bss
__attribute__((section(".heap"))) static u8 kmalloc_eternal_heap[ETERNAL_RANGE_SIZE];
__attribute__((section(".heap"))) static u8 kmalloc_pool_heap[POOL_SIZE];
static size_t g_kmalloc_bytes_eternal = 0;
static size_t g_kmalloc_call_count;
static size_t g_kfree_call_count;
static size_t g_nested_kfree_calls;
bool g_dump_kmalloc_stacks;
static u8* s_next_eternal_ptr;
READONLY_AFTER_INIT static u8* s_end_of_eternal_range;
void kmalloc_enable_expand()
{
g_kmalloc_global->enable_expansion();
@ -335,28 +329,10 @@ static inline void kmalloc_verify_nospinlock_held()
UNMAP_AFTER_INIT void kmalloc_init()
{
// Zero out heap since it's placed after end_of_kernel_bss.
memset(kmalloc_eternal_heap, 0, sizeof(kmalloc_eternal_heap));
memset(kmalloc_pool_heap, 0, sizeof(kmalloc_pool_heap));
g_kmalloc_global = new (g_kmalloc_global_heap) KmallocGlobalData(kmalloc_pool_heap, sizeof(kmalloc_pool_heap));
s_lock.initialize();
s_next_eternal_ptr = kmalloc_eternal_heap;
s_end_of_eternal_range = s_next_eternal_ptr + sizeof(kmalloc_eternal_heap);
}
void* kmalloc_eternal(size_t size)
{
kmalloc_verify_nospinlock_held();
size = round_up_to_power_of_two(size, sizeof(void*));
SpinlockLocker lock(s_lock);
void* ptr = s_next_eternal_ptr;
s_next_eternal_ptr += size;
VERIFY(s_next_eternal_ptr < s_end_of_eternal_range);
g_kmalloc_bytes_eternal += size;
return ptr;
}
void* kmalloc(size_t size)
@ -493,7 +469,6 @@ void get_kmalloc_stats(kmalloc_stats& stats)
SpinlockLocker lock(s_lock);
stats.bytes_allocated = g_kmalloc_global->allocated_bytes();
stats.bytes_free = g_kmalloc_global->free_bytes();
stats.bytes_eternal = g_kmalloc_bytes_eternal;
stats.kmalloc_call_count = g_kmalloc_call_count;
stats.kfree_call_count = g_kfree_call_count;
}

View File

@ -39,14 +39,12 @@ enum class align_val_t : size_t {};
};
void kmalloc_init();
[[gnu::malloc, gnu::returns_nonnull, gnu::alloc_size(1)]] void* kmalloc_eternal(size_t);
void kfree_sized(void*, size_t);
struct kmalloc_stats {
size_t bytes_allocated;
size_t bytes_free;
size_t bytes_eternal;
size_t kmalloc_call_count;
size_t kfree_call_count;
};

View File

@ -65,7 +65,7 @@ UNMAP_AFTER_INIT static void load_kernel_symbols_from_data(Bytes buffer)
for (size_t i = 0; i < 8; ++i)
s_symbol_count = (s_symbol_count << 4) | parse_hex_digit(*(bufptr++));
s_symbols = static_cast<KernelSymbol*>(kmalloc_eternal(sizeof(KernelSymbol) * s_symbol_count));
s_symbols = static_cast<KernelSymbol*>(kmalloc(sizeof(KernelSymbol) * s_symbol_count));
++bufptr; // skip newline
dmesgln("Loading kernel symbol table...");

View File

@ -137,7 +137,6 @@ private:
};
class MemoryManager {
AK_MAKE_ETERNAL
friend class PageDirectory;
friend class AnonymousVMObject;
friend class Region;

View File

@ -13,7 +13,6 @@
namespace Kernel::Memory {
class PhysicalRegion {
AK_MAKE_ETERNAL;
AK_MAKE_NONCOPYABLE(PhysicalRegion);
AK_MAKE_NONMOVABLE(PhysicalRegion);

View File

@ -17,7 +17,6 @@ namespace Kernel::Memory {
// The allocator uses a buddy block scheme internally.
class PhysicalZone {
AK_MAKE_ETERNAL;
AK_MAKE_NONCOPYABLE(PhysicalZone);
AK_MAKE_NONMOVABLE(PhysicalZone);

View File

@ -11,8 +11,6 @@
namespace Kernel {
class LoopbackAdapter final : public NetworkAdapter {
AK_MAKE_ETERNAL
private:
LoopbackAdapter(NonnullOwnPtr<KString>);

View File

@ -20,7 +20,6 @@ namespace Kernel {
class NetworkAdapter;
class NetworkingManagement {
friend class NetworkAdapter;
AK_MAKE_ETERNAL
public:
static NetworkingManagement& the();

View File

@ -120,7 +120,6 @@ private:
};
class KernelRng : public FortunaPRNG<Crypto::Cipher::AESCipher, Crypto::Hash::SHA256, 256> {
AK_MAKE_ETERNAL;
public:
KernelRng();

View File

@ -23,7 +23,7 @@ class AHCIController final : public ATAController
, public PCI::Device {
friend class AHCIPortHandler;
friend class AHCIPort;
AK_MAKE_ETERNAL
public:
UNMAP_AFTER_INIT static NonnullRefPtr<AHCIController> initialize(PCI::DeviceIdentifier const& pci_device_identifier);
virtual ~AHCIController() override;

View File

@ -37,7 +37,7 @@ class IDEController;
class IDEChannel : public RefCounted<IDEChannel>
, public IRQHandler {
friend class IDEController;
AK_MAKE_ETERNAL
public:
enum class ChannelType : u8 {
Primary,

View File

@ -19,7 +19,6 @@ class AsyncBlockDeviceRequest;
class IDEController final : public ATAController
, public PCI::Device {
AK_MAKE_ETERNAL
public:
static NonnullRefPtr<IDEController> initialize(PCI::DeviceIdentifier const&, bool force_pio);
virtual ~IDEController() override;

View File

@ -18,7 +18,6 @@ namespace Kernel {
class AsyncBlockDeviceRequest;
class RamdiskController final : public StorageController {
AK_MAKE_ETERNAL
public:
public:
static NonnullRefPtr<RamdiskController> initialize();

View File

@ -16,7 +16,7 @@ class RamdiskController;
class RamdiskDevice final : public StorageDevice {
friend class RamdiskController;
friend class DeviceManagement;
AK_MAKE_ETERNAL
public:
static NonnullRefPtr<RamdiskDevice> create(const RamdiskController&, NonnullOwnPtr<Memory::Region>&& region, int major, int minor);
virtual ~RamdiskDevice() override;

View File

@ -22,7 +22,6 @@ namespace Kernel {
class AsyncBlockDeviceRequest;
class StorageDevice;
class StorageController : public RefCounted<StorageController> {
AK_MAKE_ETERNAL
public:
virtual ~StorageController() = default;

View File

@ -19,7 +19,6 @@ namespace Kernel {
class PartitionTable;
class StorageManagement {
AK_MAKE_ETERNAL;
public:
StorageManagement();

View File

@ -14,7 +14,6 @@
namespace Kernel {
class ConsoleManagement {
AK_MAKE_ETERNAL;
friend class VirtualConsole;
public:

View File

@ -15,7 +15,6 @@ namespace Kernel {
class MasterPTY;
class PTYMultiplexer final : public CharacterDevice {
AK_MAKE_ETERNAL
public:
PTYMultiplexer();
virtual ~PTYMultiplexer() override;

View File

@ -47,7 +47,6 @@ private:
class VirtualConsole final : public TTY
, public KeyboardClient
, public VT::TerminalClient {
AK_MAKE_ETERNAL
friend class ConsoleManagement;
friend class DeviceManagement;
friend class ConsoleImpl;

View File

@ -29,7 +29,6 @@ enum class TimePrecision {
};
class TimeManagement {
AK_MAKE_ETERNAL;
public:
TimeManagement();

View File

@ -87,7 +87,6 @@ void MemoryStatsWidget::refresh()
auto json_result = JsonValue::from_string(file_contents).release_value_but_fixme_should_propagate_errors();
auto const& json = json_result.as_object();
[[maybe_unused]] u32 kmalloc_eternal_allocated = json.get("kmalloc_eternal_allocated").to_u32();
u32 kmalloc_allocated = json.get("kmalloc_allocated").to_u32();
u32 kmalloc_available = json.get("kmalloc_available").to_u32();
u64 user_physical_allocated = json.get("user_physical_allocated").to_u64();