1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 15:28:11 +00:00

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
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
#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; using std::nothrow;
inline void* kmalloc_array(Checked<size_t> a, Checked<size_t> b) inline void* kmalloc_array(Checked<size_t> a, Checked<size_t> b)

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -11,7 +11,6 @@
namespace Kernel { namespace Kernel {
class NullDevice final : public CharacterDevice { class NullDevice final : public CharacterDevice {
AK_MAKE_ETERNAL
friend class DeviceManagement; friend class DeviceManagement;
public: 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 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()) if (!is_available())
s_the = serial_device; 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()); dmesgln("PCISerialDevice: Found {} @ {}", board_definition.name, device_identifier.address());

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -403,7 +403,6 @@ private:
JsonObjectSerializer<KBufferBuilder> json { builder }; JsonObjectSerializer<KBufferBuilder> json { builder };
json.add("kmalloc_allocated", stats.bytes_allocated); json.add("kmalloc_allocated", stats.bytes_allocated);
json.add("kmalloc_available", stats.bytes_free); 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_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_available", system_memory.user_physical_pages - system_memory.user_physical_pages_used);
json.add("user_physical_committed", system_memory.user_physical_pages_committed); json.add("user_physical_committed", system_memory.user_physical_pages_committed);

View file

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

View file

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

View file

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

View file

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

View file

@ -47,7 +47,6 @@ enum RegisterIndex {
class IntelNativeGraphicsAdapter final class IntelNativeGraphicsAdapter final
: public VGACompatibleAdapter { : public VGACompatibleAdapter {
AK_MAKE_ETERNAL
public: public:
struct PLLSettings { struct PLLSettings {
bool is_valid() const { return (n != 0 && m1 != 0 && m2 != 0 && p1 != 0 && p2 != 0); } 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 class VGACompatibleAdapter : public GenericGraphicsAdapter
, public PCI::Device { , public PCI::Device {
AK_MAKE_ETERNAL
public: 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_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&); static NonnullRefPtr<VGACompatibleAdapter> initialize(PCI::DeviceIdentifier const&);

View file

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

View file

@ -29,7 +29,6 @@ static constexpr size_t CHUNK_SIZE = 64;
#endif #endif
#define POOL_SIZE (2 * MiB) #define POOL_SIZE (2 * MiB)
#define ETERNAL_RANGE_SIZE (4 * MiB)
namespace std { namespace std {
const nothrow_t nothrow; 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)]; alignas(KmallocGlobalData) static u8 g_kmalloc_global_heap[sizeof(KmallocGlobalData)];
// Treat the heap as logically separate from .bss // 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]; __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_kmalloc_call_count;
static size_t g_kfree_call_count; static size_t g_kfree_call_count;
static size_t g_nested_kfree_calls; static size_t g_nested_kfree_calls;
bool g_dump_kmalloc_stacks; 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() void kmalloc_enable_expand()
{ {
g_kmalloc_global->enable_expansion(); g_kmalloc_global->enable_expansion();
@ -335,28 +329,10 @@ static inline void kmalloc_verify_nospinlock_held()
UNMAP_AFTER_INIT void kmalloc_init() UNMAP_AFTER_INIT void kmalloc_init()
{ {
// Zero out heap since it's placed after end_of_kernel_bss. // 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)); 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)); g_kmalloc_global = new (g_kmalloc_global_heap) KmallocGlobalData(kmalloc_pool_heap, sizeof(kmalloc_pool_heap));
s_lock.initialize(); 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) void* kmalloc(size_t size)
@ -493,7 +469,6 @@ void get_kmalloc_stats(kmalloc_stats& stats)
SpinlockLocker lock(s_lock); SpinlockLocker lock(s_lock);
stats.bytes_allocated = g_kmalloc_global->allocated_bytes(); stats.bytes_allocated = g_kmalloc_global->allocated_bytes();
stats.bytes_free = g_kmalloc_global->free_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.kmalloc_call_count = g_kmalloc_call_count;
stats.kfree_call_count = g_kfree_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(); void kmalloc_init();
[[gnu::malloc, gnu::returns_nonnull, gnu::alloc_size(1)]] void* kmalloc_eternal(size_t);
void kfree_sized(void*, size_t); void kfree_sized(void*, size_t);
struct kmalloc_stats { struct kmalloc_stats {
size_t bytes_allocated; size_t bytes_allocated;
size_t bytes_free; size_t bytes_free;
size_t bytes_eternal;
size_t kmalloc_call_count; size_t kmalloc_call_count;
size_t kfree_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) for (size_t i = 0; i < 8; ++i)
s_symbol_count = (s_symbol_count << 4) | parse_hex_digit(*(bufptr++)); 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 ++bufptr; // skip newline
dmesgln("Loading kernel symbol table..."); dmesgln("Loading kernel symbol table...");

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -29,7 +29,6 @@ enum class TimePrecision {
}; };
class TimeManagement { class TimeManagement {
AK_MAKE_ETERNAL;
public: public:
TimeManagement(); 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 json_result = JsonValue::from_string(file_contents).release_value_but_fixme_should_propagate_errors();
auto const& json = json_result.as_object(); 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_allocated = json.get("kmalloc_allocated").to_u32();
u32 kmalloc_available = json.get("kmalloc_available").to_u32(); u32 kmalloc_available = json.get("kmalloc_available").to_u32();
u64 user_physical_allocated = json.get("user_physical_allocated").to_u64(); u64 user_physical_allocated = json.get("user_physical_allocated").to_u64();