#charmOS

1 messages Β· Page 4 of 1

eager yew
#

maybe i'll do that tho

steel herald
#

yeah its kind of a tough format

#

a package of packages of structs

#

so yeah try real hw or look around

eager yew
#

i did not see it in managarm

steel herald
#

you would be the first

eager yew
#

whaaat

steel herald
#

managarm doesnt have any power management

eager yew
#

no pmm trl

steel herald
#

even obos which supports suspend to ram and wake doesnt have c state stuff

eager yew
#

do they not want to do it or is this difficult

steel herald
#

just not a priority for anyone

eager yew
#

understandable

#

I suppose I shall sift through linux

steel herald
#

iirc by default the cpu runs in the slowest safest config

eager yew
#

but they use acpica so idk

steel herald
#

and it works for most people

steel herald
eager yew
#

looks like lenox has drivers/acpi/processor_idle.c

steel herald
#

yeah u need to take a look at this

#

for the firmware to expose c state control to u

eager yew
#

if (!processor_physically_present(handle)) huh what an odd check to perform

steel herald
#

not odd at all lol

#

some firmware has 9999 processor objects

#

only some of them map to real cpus

eager yew
#

oh right yes firmware is cooked and broiled half the time

#

understandable

steel herald
#

its mostly so they can reuse the same code for different cpus

eager yew
#

im pretty sure limine even had cases where the LAPIC addresses were missing from the madt which is kinda sily

#

ok yes this is great tho i'll look at lenox

steel herald
#

yeah this shouldnt be that hard at all

#

just some code

eager yew
#

yup looks like it's just a "first bother _OSC and then go find C states"

steel herald
#

claim control via fadt

steel herald
#

first u tell the platform u can do that

eager yew
#

all this to make my idle thread idle better

#

sounds good

steel herald
#

well u can also make your cpu run faster as well

eager yew
steel herald
#

maybe, ive never written a driver for this stuff

#

are P states managed via this thing also?

steel herald
#

ah

eager yew
#

lol _PPC

steel herald
#

looks like they're similar

#

so u can support both

eager yew
#

I don't think the single piece of hardware I'm running this on actually supports P states since the CPU can't overclock but I'll probably support it anyways just like how I plan to support XHCI even though that laptop (ThinkPad T400) is EHCI

πŸ˜ƒ yippeee

#

I'll do c-states first tho

steel herald
#

then we can use your code as an example of p/cstate management

eager yew
#

very tragic that this has not been done by any hobby kernel before with uacpi

#

no 9GHz overclock on mammogram OS

steel herald
#

might be done by react os soon

#

but that has 9999 layers of abstraction and indirections

#

so not that great of an example for hobby

eager yew
#

do they support C states over there

steel herald
#

you'd have to ask @restive laurel

eager yew
#

or I can just cd reactos && grep -rine "_CST"

#

I'll do the latter first

#

lets seeeee

steel herald
#

since its NT it might do 'TSC_' or whatever

eager yew
#

uh oh

steel herald
#

they like doing char literals

eager yew
#

interesting

steel herald
#

thats acpica code

eager yew
#

oh wait nvm yea

#

i am not seeing anything about c states in reactos

#

sadg

#

linux it is then

steel herald
#

freebsd might have it if u like reading that more

eager yew
#

i was just thinking that yes

#

idk if they have their acpi stuff in freebsd-src tho

#

prob somewhere else

steel herald
#

well not might, it does 99%

#

wdym, why wouldnt it

eager yew
#

o nvm they do, they just dont have something like an explicit drivers/ dir

steel herald
#

their dir structure is a bit peculiar yes

eager yew
#

freebsd-src/sys/dev/acpica/acpi_cpu.c

#

maybe idk

#

ya i think that's it

#

it's not acpica sources tho so funny to call the directory acpica

steel herald
#

Probably because its so tied to the api idk

#

But yeah strange choice

restive laurel
#

It’s going to be a while till everything boils down. It looks correct in the right spots

#

What’s in master right now is totally wrong still

eager yew
#

I guess I might need to get that up and running soon

restive laurel
#

C states?

eager yew
#

yea

restive laurel
#

I would

eager yew
#

freebsd C-state code is nice

#

it seems to be a little different from lenox

steel herald
eager yew
#

I just find it a bit cleaner

#

and more commented

steel herald
eager yew
#

TIL C allows this lol, never written code like that but that's funny

steel herald
#

why wouldnt it

eager yew
#

no idea i just never thought it would πŸ’₯

eager yew
#

ok today is going to be the Great And Fun Time of either writing ASL myself or finding existing tables with C states

#

I shall first attempt the latter

#

or I'll probably just ditch this and do XHCI since that's a saner endeavor

eager yew
#

yeah nah we're doing XHCI today this ACPI source language thing is actually bad

eager yew
#

right yea, xhci, i got the ADDRESS_DEVICE command working

#

I need some generic USB interface abstraction since I'll also write an EHCI driver since that's what my hardware uses

#

problem for later tho

#

lmao why did i write this

#

"We have if statements at home"

#

whoopsie

#

i might start getting sick and tired of these logs soon

#

idk I'll figure something out

#

spinning cat loading screen next

#

I think indenting them will make things look more pleasant so it'll be like

[CATEGORY]: Found device
    Message
    Message
[CATEGORY]: Initialized``` idk
#

why is the usb 2.0 spec lying about page numbers

#

that's weird

#

this is supposedly on page 248

#

but it's on page 276

#

can't even trust table of contents these days πŸ’”

#

πŸ€ͺ

#

oh wait no need for the clang-format commands it doesnt break the comment

#

nice

steel herald
eager yew
#

hmmmm yea nvm

#

thanks for the suggestion once again

steel herald
#

yep thats what i meant

eager yew
#

binary

#

😒 it ok but also lowkey annoying

eager yew
#

lol that is a silly way to represent numbers

eager yew
#

for historical reasons

eager yew
#

I got the GET_DESCRIPTOR command to work

#

chat, is this real

#

setup -> complete

#

QEMU gotta be my favorite hardware manufacturer

#

QEMU is indeed my favorite hardware manufacturer

#

gonna port mintia mousetest to this OS trl

#

A USB and Firewire Host Controller Interface (UFHC) is a register-level interface that enables a host controller for USB or IEEE 1394 hardware to communicate with a host controller driver in software. The driver software is typically provided with an operating system of a personal computer, but may also be implemented by application-specific dev...

#

The OHCI standard for USB is similar to the OHCI standard for IEEE 1394, but supports USB 1.1 (full and low speeds) only; so as a result its register interface looks completely different. Compared with UHCI, it moves more intelligence into the controller, and thus is accordingly much more efficient; this was part of the motivation for defining it. If a computer provides non-x86 USB 1.1, or x86 USB 1.1 from a USB controller that is not made by Intel or VIA, it probably uses OHCI (e.g. OHCI is common on add-in PCI Cards based on an NEC chipset). It has many fewer intellectual property restrictions than UHCI.[2] It only supports 32-bit memory addressing,[3] so it requires an IOMMU or a computationally expensive bounce buffer to work with a 64-bit operating system.[citation needed] OHCI interfaces to the rest of the computer only with memory-mapped I/O.[3]

#

blistering speed

#

ok now I need to figure out how to make my usb drivers themselves controller agnostic

#

so that means, first, I need an abstraction layer for controllers to present simple functions to send usb packets

Then, I'll also need to have an abstraction layer for the controller to set/unset interrupts for devices

I'll also need per-controller ways to rig up interrupts so that things like USB device plug/unplug can be detected and adjusted for

So, my individual USB drivers are fully controller agnostic, but they interact with controller-provided function pointers/methods to perform actions and receive interrupts

So the general flow becomes

XHCI controller init -> XHCI registers all its USB devices somewhere -> USB device init -> USB devices do things

Then, on an unplug

XHCI controller catches the interrupt -> XHCI controller figures out who was unplugged, and has some way to signal to the higher level USB driver "Hey, destroy yourself, you're gonna be gone anyways" -> USB driver cleans up structures -> USB driver says "OK I am done" and XHCI controller goes "Alrighty I'll clean up for good now" -> XHCI controller cleans up internal structures related to that USB device

and on hotplug

XHCI controller catches the interrupt -> XHCI controller allocates structures and enables the new port and allows it to be addressed -> USB device is initialized -> USB device is up

#

this will be fun

eager yew
#

alrighty back to usb stuff today I clean things and introduce interrupt driven responses and start making abstractions

eager yew
#

right yes usb ok great something like this should be ok

struct usb_controller_ops {
    bool (*submit_control_transfer)(struct usb_controller *ctrl, uint8_t port,
                                    struct usb_packet *pkt);
    bool (*submit_bulk_transfer)(struct usb_controller *ctrl, uint8_t port,
                                 struct usb_packet *pkt);
    bool (*submit_interrupt_transfer)(struct usb_controller *ctrl, uint8_t port,
                                      struct usb_packet *pkt);

    bool (*reset_port)(struct usb_controller *ctrl, uint8_t port);
    bool (*get_device_descriptor)(struct usb_controller *ctrl, uint8_t port,
                                  struct usb_device_descriptor *out);

    bool (*get_string_descriptor)(struct usb_controller *ctrl, uint8_t port,
                                  uint8_t string_index, char *buf, size_t len);

    void (*ring_doorbell)(struct usb_controller *ctrl, uint8_t slot,
                          uint8_t ep);
};```
#

πŸ’₯

#

was busy earlizer

gentle gazelle
#

get_*_descriptor probably does not need to go in the controller ops

#

since you cna just do it with control transfers

eager yew
#

oh yea true

gentle gazelle
#

also control transfers need more parameters probably? or are you planning on having the special values at the start of the packet

eager yew
#

uhh I haven't fully planned out the abstraction layer so this will gradually get more improvements over time

#

I just want some sort of a foggy idea

#

I got the device string descriptors yesterday

eager yew
#

gameplay

#

nice

eager yew
#

mfw I can't just leak memory in device init for USB because these are removable and I actually have to keep track of allocated objects to free them when the device is unplugged

#

it's going good rn

#

made linker section for usb drivers

#

πŸ’₯

eager yew
#

the grind is real

#

I shall prob go nap nap now tho

#

this is so much fun

#

I will have such a blast with the TCP stack impl next

#

once I implement the Fun Times of demand paging I might become the Page Fault Shill idk

#

i have yet to see a page fault shill here

eager yew
#

ok i kind of have absolutely zero user input via keyboard stack so i will just not do that and mount a usb stick instead and see if i can poke it

#

SUPER SPEED

#

⚑

eager yew
#

i checked my git blame and apparently I have accidentally fully "ship of theseus'd" my codebase

#

that's kinda funny

#

subconsciously performing a rewrite on nearly every file

short lichen
eager yew
#

i went to moovies so no usb work today

#

tryna set up the interrupt stuff

short lichen
eager yew
#

i love joseph quinn i love pedro pascal

short lichen
eager yew
#

pascal mentioned

short lichen
#

My brain commited suicide

eager yew
short lichen
eager yew
#

not very much

short lichen
short lichen
#

Oh yeah did you see the ending credits

eager yew
#

every time you reach a new point, it goes "Forget everything you were taught last year"

eager yew
short lichen
#

There are 2 apparently

#

I saw both because of the friend who invited us

eager yew
short lichen
eager yew
#

what was the other one

short lichen
#

I won't spoil the second one

eager yew
#

aw darn

#

ts pmo i am not rewatching allat

short lichen
#

Just pirate the movie and mmap it backwards to watch the end

eager yew
#

mmap it backwards is crazy

eager yew
#

are you superpositioning all over the place rn

short lichen
#

Next is the college level physics

#

Heat equations and fuck not

#

I like physics its a chill subject

eager yew
short lichen
eager yew
short lichen
#

Physics is applied maths yeah

stuck nexus
short lichen
#

Engineering is applied physics

eager yew
#

*friends who actually do this stuff and dedicate much of their time to it

#

prime numbers my beloved

short lichen
#

Pure math is like that yeah

eager yew
short lichen
short lichen
#

I thought it had to be unique

eager yew
#

ah ok

short lichen
#

Then isn't that just prime factorization

stuck nexus
eager yew
#

sounds great

stuck nexus
#

its weird that im going to get to the end of the general math track up to the point where people start like, specializing

#

if theyre a math major

eager yew
#

what are you majoring in

stuck nexus
#

cs

short lichen
#

I'm guessing cs

#

Yeah

eager yew
#

shocking discovery

eager yew
#

what part of it

short lichen
eager yew
short lichen
eager yew
#

civil engineering trl

short lichen
short lichen
eager yew
eager yew
short lichen
#

I had Maths Physics Chemistry and English

#

And I like computers

stuck nexus
short lichen
#

What could be my 5th subject

stuck nexus
#

which is scary

eager yew
#

computer engineering

short lichen
#

Well it was Economics lmao

eager yew
#

I was close with botany

#

do you like gardening

#

i love my garden

short lichen
#

You'd be close if you said biology there are people who do PCMB

short lichen
#

I mean

eager yew
#

it's like that roblox grow a garden game but it's real life 😲

short lichen
#

Sure ig

#

But h

short lichen
eager yew
short lichen
#

I don't understand the point of these farming/gardening simulators

#

It's just waiting glorified as a game

eager yew
#

me neither i wrote a program to automate it

eager yew
short lichen
eager yew
#

my end goal with this OS is to port every version of fnaf and run them all at the same time

short lichen
#

Lmao

eager yew
#

i think it's a good test and a solid goal because of everything needed to make that happen

#

also funny

short lichen
#

I want to currently get some GTA game running on this

#

There used to be Re3 but then it got DMCAed

eager yew
#

for igpu

short lichen
#

Banger

eager yew
#

game on your motherboard's beeper next

eager yew
#

didnt u start ur kernel even earlier than me in terms of the age u were when u started it

#

locked in

short lichen
#

But locked in when I was 15-16

eager yew
eager yew
short lichen
#

Neptune was even younger

#

I think she was 13

eager yew
#

programming in the womb

eager yew
short lichen
#

And vfs

eager yew
#

oh ok understandable

eager yew
#

22k sloc

#

awesome

eager yew
#

oh ok

#

coz like mine is creeping up on 20k sloc (it's at like 19.5) so i am mildly concerned

#

concerned that i have way too much code

#

but pretty much everything is used so idk

#

and i've only been at this for 2 months so as time passes this number will definitely be going up a considerate amount

#

no more 10 second cleanbuild times πŸ’”

stuck nexus
#

You guys have your own operating systems????

eager yew
#

nope

#

this is not an OS and it's barely a kernel

#

it's only a "Small C program" at the current stage

stuck nexus
#

i wish i could do that

#

Most complicated thing I ever made was when I put da garlic in da tuna

eager yew
#

yeah me too actually, most complicated thing i ever made was fried rice with chicken

#

not chicken fried rice tho im not a chicken

short lichen
#

Paneer chilli bro very hard to make

stuck nexus
#

so you def dont have too much code

eager yew
#

I have just realized that my thread priorities may put me in a bit of a pickle for userspace tools like nice that expect more fine grained control

#

I might migrate away from multiple lists at queue levels to having multiple red black trees, with the thread classes of URGENT, RT, TS, and BG each having one red black tree, where the threads have a priority_at_level from 0-255 to place themselves in the tree

this way if I have a thread at the TS priority things like nice can actually do something meaningful with the thread priority

#

"we have cfs at home"

eager yew
#

so to avoid starvation, my idea is that I would need to do something like keep track of a thread's runtime activity

threads that are mostly blocking would get "nudged" to higher priority levels in a priority class, since those are more likely to be more interactive, whereas threads that are fond of processor time would get "nudged" to lower priority levels in a class because they are more likely to be long running and rarely IO bound

I think a decent way to handle this is to have perceived thread activity classes, so things like THREAD_ACTIVITY_CLASS_IO_BOUND and such, and have these just "nudge" the priority at their priority class, where I have some heuristic that takes into account a whole bunch of other stuff including the activity class to essentially figure out the most ideal priority_at_level to assign to the thread

so it would be 3 main parts

  1. detecting what the thread's activity class is
  2. figuring out what priority_at_level to give it
  3. figuring out how to keep track of a thread's activity class history so that changes in activity class can be biased based on what the past activity was like.

this way if a thread were to move to IO BOUND after previously being CPU BOUND for a while, that move would be "nudged" in a direction that would require more IO BOUND activity for it to truly change activity classes, compared to a thread that was IO BOUND, then became CPU BOUND, and is now becoming IO BOUND again

the actual thread picking logic is entirely unaware of these activity classes, and just picks based on priority_in_level, but the gradual decay would make it so that threads would always get a chance to run

I could set this up so that every thread would absolutely 100% have to have some point in time where it sits at one of the lowest priorities in its class, so that other threads have a guarantee that they are run

#

this is so silly

#

I think I have a better excuse for using that FFNN in the kernel now lmao

#

finally the AI OS

#

so it's an """"MLFQ"""" with a """"cfs"""" at each level

#

"a little bit of this a little bit of that"

eager yew
#

I can probably keep ringbuffers for block/sleep/wake reasons, with each ringbuffer also being associated with a small 'histogram' countaing the number of each reason

#

for activity class

wraith pilot
#

have you looked at how ule does this?

#

might save you some time

eager yew
#

they have slptime and runtime and ts_ticks

#

so their heuristic is

"Sleeping for 80% of the last 5 seconds?" -> boost to interactive

#

I think this would work ok

but I also would like to track more data since I can tag each sleep/wake reason with a timestamp and essentially accomplish the same task but potentially expand upon this

this way I can use the other data for more info if I have a use for it in the future

#

I will probably drop the "Multiple RBTs for each priority" idea because there are two priorities (URGENT and BACKGROUND) that are only used in kernel threads and have absolutely no reason to have those more complex heuristics

so for those two I can stick with what I have where I have the lists/queues

then I'll just have two RBTs, one for RT one for TS

#

honestly I'll probably just do one RBT for TS threads only come to think of it

eager yew
#

I wonder why container_of isnt just a default gcc extension or something

#

whaetever

eager yew
# eager yew so their heuristic is "Sleeping for 80% of the last 5 seconds?" -> boost to in...

I think I will just do freebsd's tracking logic + the ringbuffers so I can have coarse_stats and the ringbuffers, and say something like

if (sleep_percent > 80% over last 5 sec)
    classify = INTERACTIVE;
else if (frequent short bursts of wakeup/sleep in ringbuffers with intervals < 50 ms)
    classify = INTERACTIVE or IO_BOUND;
else if (mostly running in coarse_stats and ringbuffer shows no blocking)
    classify = CPU_BOUND;

idk

#

I could potentially be able to get away with having it run tickless by just tracking sleep and wake times and reasons

#

perhaps

eager yew
#

this will truly be a blast

wraith pilot
#

cool, good luck with that

#

I couldnt read half of it due to discord not wanting to scroll horizontally

placid vessel
eager yew
#

the event reasons for things work

#

πŸ’₯

placid vessel
eager yew
#

ULE for thread activity classes and CFS for periods and the RBT

eager yew
#

using per-second buckets to track coarse-grained history for the past 10 seconds so that I can still get complete data

#

20kloc nice

#

finally back to a number that starts with 2

eager yew
#

oh yeah I finally fixed a super rare transient deadlock that was bothering me (I think)

#

super complicated fix

static void do_wake_other_core(struct scheduler *target, uint64_t core_num) {
    if (!target->timeslice_enabled)
        lapic_send_ipi(core_num, IRQ_SCHEDULER);
}``` extremly complex
#

a whole singular if statement

eager yew
#

literally nvme

#

who needs slot machines when you have race conditions

#

ok great today I got the thread activity logging infra all working and everything seems to be going fine and dandy so tomorrow I figure out how to classify threads

slim raft
#

Oh I really like this so far

eager yew
#

πŸ’₯

#

fun tho

molten night
#

That's okay, no one really need userspace

eager yew
#

had a "Local Man Crashes Out Because His Thread Struct Is Already 210 Bytes In Size" moment

#

it ok though

#

hopefully it is not super bad

#

I can probably remove these two and get it back down below 200

#

along with the lock (dunno why I put that there tbh)

#

nice it's 192 bytes now hooray

eager yew
#
block_count 14, sleep_count 0, wake_count 14, block_duration 1, sleep_duration 0, wake duration 872``` i hope this is enough data for activity classification per thread, idk might add more tracking if needed, but I have logs like this for each second for the past 16 seconds
#

always gotta keep stuff a power of 2 fr

#

otherwise compiler optimizations no work for the modulo

stuck nexus
#

yours aint that bad

eager yew
#

oh ok phew

eager yew
#

big

#

how curious

#

__u64 vs u64

vagrant cedar
#

Why are you worried about your thread struct being large?

stuck nexus
vagrant cedar
#

No

#

This is premature optimization

stuck nexus
#

"premature optimization" is bad when youre jumping through crazy hoops to try to optimize a case that might not even turn out to be a bottleneck or something like that

#

doing relatively low effort optimization from the jump is good though

#

i noticed ppl have a tendency to overfit to like the names of things that are considered bad practice

#

like "premature optimization is the root of all evil" and "goto considered harmful" must mean that i should get upset if i see somebody optimizing anything early and get upset if goto ever appears in a codebase

#

little bit more case-by-case critical thinking would be good probably

#

for example if you have to go waaaaay out of your way to optimize something that its not at all clear will be an issue in practice, especially if there are complex trade-offs involved, you probably shouldnt

#

but imo its absolutely good practice to just along the way try to be non-stupid and thereby minimize the number of things cropping up later

#

especially wrt overall design but also trivial details that can add up if you dont pay attention to them early, where you might later have a lot of out-of-line backtracking to do in your project, when it could have been avoided in-line with the work youre doing right now. in the former circumstance you now have to pay extra energy and time for mental context switching and your net productivity is lower. you're also more likely to miss details when backtracking than when youre already deeply thinking about the component which could result in lower quality code

#

and it falls in the category of, easy way to straightforwardly improve quality now and avoid potential issues down the line, to just try to be careful with structure sizes

eager yew
placid vessel
eager yew
#

idk some threads just have one page of stack since they don't need more

placid vessel
#

crayz

#

how do you determine how much they need tho

eager yew
placid vessel
eager yew
#
struct thread *thread_create(void (*entry_point)(void));
struct thread *thread_create_custom_stack(void (*entry_point)(void),
                                          size_t stack_size);```
#
struct thread *thread_create(void (*entry_point)(void)) {
    return create(entry_point, STACK_SIZE);
}

struct thread *thread_create_custom_stack(void (*entry_point)(void),
                                          size_t stack_size) {
    return create(entry_point, stack_size);
}``` ezpz
#

I should probably rename STACK_SIZE πŸ’₯

eager yew
#

I forgor I needed to implement rcu

#

doing that right after this scheduler stuff

eager yew
#

I have just realized I have done a Major Stupid by not building a faster arena allocator that uses 2MB pages so that for things like page sized page aligned DMA buffers and thread stacks and stuff, I don't need to constantly keep calling into paging code and can just nab pages out of a 2MB arena

#

πŸ’₯ oopsie daisies new todo list task acquired

eager yew
#

methinks I can get away with an AVL tree to keep track of 2MB pages with a bitmap for each 2MB page indicating used/freed 4KB portions, and I can "refcount" each 2MB page such that it is completely freed and unmapped and the corresponding structure is deallocated once everything from it is freed

#

πŸ’₯

#

ok so then the plan for the global hugepage allocator would be to create a tree structure to keep track of all hugepages across all cores, with a small lock for tree modifications, and then keep smaller trees of partially/fully free hugepages per-cpu that are marked as such in the global tree structure (each struct just has a core if it's owned by any)

then each cpu would just find a 2mb hugepage from its core-local structure, and allocate and refcount it, whilst still maintaining it in the global tree structure

and when anything needs to be allocated, I only need to lock for the potential tree modification, (which may be rare since 2MB is 512 x 4KB)

I can keep a small lock around each hugepage, but it will probably be pretty uncontended, and this is just so that I can defer a free from one core to another

and to handle the very rare scenario where one processor has a lock on a hugepage because it's freeing it since the refcount dropped to zero, and another processor came in to allocate said page, I can simply make allocations use a trylock on a hugepage whereas frees will use full, spinning locks so that if one processor allocating a hugepage sees that the lock is held it gives up (preventing the UAF, I think)

#

bro is a yapper

#

I probably wanna use rcu here tbh

#

I can probably honestly get away with lists for each core's local hugepages since I'm most likely only going to have a few of those active at a time, and the overhead of a tree structure is probably not worth it here

#

but I'll keep the tree for tracking everything everywhere

#

I can probably do an optimization in the future where I lazily free hugepages. for example, if I just recently freed a hugepage and removed it from the tree structure, rather than immediately calling the buddy allocator to free the physical pages and calling the virtual unmap function, I can add it to some known list of free hugepages that are marked for deletion. this way, if I suddenly encounter a scenario where I need a new hugepage, I just take one from this global list rather than doing the whole call into the buddy allocator

I can pair something like a deferred timer interrupt event with these pages marked for deletion, so that after some time, they get "garbage collected" depending on the memory pressure at the time of enqueue

for example I could keep track of the amount of calls into this allocator in the past X seconds. if this number is high, that means this page i just freed has a higher chance of being used again, so I preserve it for longer. but if the number is low, then there is likely not much happening with the allocator so I can set a much shorter wait period before tossing the page

πŸ’₯

#

I can't believe this is the third time I've reinvented garbage collection

#

such is programming

#

since I'm doing the per core thingamajig I can probably start making the buddy allocator numa aware for no reason

eager yew
#

i will probably steal many of these ideas over to the slab allocator but this is bigger priroity 4 now

eager yew
#

i kinda sorta dont wanna write an avl tree impl or steal an avl tree impl for this, and since i have a full, working rbt impl i'll just nab that

#

maybe will write avl tree impl later

eager yew
#

ok cool bean i got the buddy allocator working and tests are still blazingly πŸš€ fast πŸš€ which is very neat so now I start building the hugepage allocator

#

wait a second my filesystem integration test just got 2 milliseconds faster

#

how curious lol

#

very funny

eager yew
#

anyway got the read copy update thing working

#

time to do the hugepage allocator

eager yew
#

yeah ok I can absolutely make this NUMA aware for fun since I'm making memory things core-local and I can just make my physical memory buddy allocator do that too

#

this will be so silly

#

and then for stuff like thread migration I just give each core a list of numa neighbors and only walk that list

#

πŸ’₯

eager yew
#

my vm that i used to work on this project on windows just vanished but that's ok i can just set up wsl and i have all commits pushed anyways

#

πŸ€ͺ

eager yew
eager yew
#

ok I think if I implement the hugepage allocator I can shave another 1.5ish milliseconds off of my filesystem integration test since that's how much time it spends allocating things since the buffers are large

#

fire

#

started at 50ms now at 4ms hopefully can get it down to 2 or 3

eager yew
#
unsafe extern "C" {
    pub unsafe fn kmalloc(n: usize) -> *mut u8;
    pub unsafe fn kfree(ptr: *mut u8);
}

use core::alloc::{GlobalAlloc, Layout};
pub struct PeterGriffin;

unsafe impl GlobalAlloc for PeterGriffin {
    unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
        let size = layout.size();
        unsafe { kmalloc(size) }
    }

    unsafe fn dealloc(&self, ptr: *mut u8, _: Layout) {
        unsafe {
            kfree(ptr);
        }
    }
}``` rust πŸ‘
vagrant cedar
#

Your kernel gets Rusty?

eager yew
#

gonna be using it soon though

#

perhaps

vagrant cedar
eager yew
# vagrant cedar <:chad:815144781842743334>

I will probably use a fallible allocator crate, or use the nightly fallible allocator for rust because I don't want a kernel panic when a userland program cannot be started due to OOM

do you recommend a crate or the nightly feature

vagrant cedar
#

I use tons of nightly shit but no crates

#

Actually no

#

I use tock-registers and crc

#

Also I should at some point figure out how to make the default for things that alloc be a Result, instead of panicking

eager yew
vagrant cedar
#

No

#

Not always at least

eager yew
#

πŸ’”

vagrant cedar
#

The official alloc crate isn't very good at doing that unfortunately, and there's no way to disable all functions that may panic on alloc.

#

Honestly I was just gonna make my own abstractions for allocation at some point

vagrant cedar
#

Oh bru

#

I should just use fallible_alloc crate

eager yew
#

revolutionary findings

vagrant cedar
#

Actually no

#

That doesn't do what I want

#

I want to ban all functions that could panic on OOM

eager yew
#

crash out

#

odd

#

macos qemu being funny with acpi probably

#

was not happening b4

#

hmmmm i updated qemu and problem still happen

#

funky

#

ci/cd does fine so it is probably a local problem

#

yeah idk it just keeps being weird with the macos host

#

works fine in CI/CD

#

not on macos tho πŸ’₯

#

bruh i have to boot my linux vm on the mac since macos qemu is just being odd with uacpi

#

rip

#

ok seems like lemonlime bootloader is giving me a weird rsdp address

#

on macos it seems to be 0xffff8000000f5270 which is not a physaddr

#

funky

#

ohhh ok i thinsk i fixed it a bit

#

nvm acpi still being strange

#
>> UACPI ERROR: Op 0x0002 ('Reserved_0x02'): invalid/unexpected opcode

>> UACPI ERROR: aborting method invocation due to previous error: invalid AML opcode

>> UACPI ERROR:     #0 in \()``` why is exclusively my macos machine weird πŸ’”
#

literally what is this baloney it does fine in ci cd

#

perplexing

#

literally what is this baloney it functions just fine on CI/CD with linux and just dies with macOS

#

πŸ’₯

#

qemu is being odd probablyh

#

yea ok it's definitely a problem on macOS qemu

#

this is so odd

eager yew
#

ok yes literally none of my other machines have that problem macOS qemu is just being extremely peculiar

#

so odd

#

no more kernel dev for 5 days then because that is how long I will be away from home (and thus using the macbook with cursed acpi behavior)

I will probably spend that time implementing data structures and then porting them to kernel πŸ‘

#

minor setback

eager yew
#

I really hope this is not the case though but it seems the most likely

#

uacpi last update was months ago so it's not at fault here (this was an issue I only started seeing today)

#

bruh

#

me when I update qemu in 2 weeks and the bug goes away

#

gonna revert qemu now to see if it really is the problem

#

brew is being funny and doesnt let me revert to an old version πŸ’”

#

i wonder why package managers do this, like arch linux pacman does the same thing and only retains the most recent version of most packages on remote

#

portage doesnt πŸ’₯

molten night
#

Ill once again shill for building qemu from source

eager yew
#

Device emulation and assignment
ACPI / SMBIOS
Workaround 'PCI Label Id' Windows bug, which is normally harmless but on localized versions can lead to guest hangs (commit 0b053391985)

bruh lol it seems like their most recent version made an acpi change

#
>> UACPI ERROR: unable to lookup named object 'οΏ½οΏ½οΏ½' within (or above) scope '\_SB_.PCI0': invalid AML name string

>> UACPI LOG: unable to lookup named object 'οΏ½οΏ½οΏ½' within (or above) scope '\_SB_.PCI0': invalid AML name string

>> UACPI ERROR: aborting method invocation due to previous error: invalid AML name string

>> UACPI LOG: aborting method invocation due to previous error: invalid AML name string

>> UACPI ERROR:     #0 in \()

>> UACPI LOG:     #0 in \()``` ah it seems to be pci related
#

rip

#

the patch shows these new lines of code for qemu

    {
       Aml *pkg = aml_package(2);

       aml_append(ifctx, aml_store(aml_call2("AIDX", bnum, sunum), acpi_index));
       aml_append(ifctx, aml_store(pkg, ret));
       /*
        * Windows calls func=7 without checking if it's available,
        * as workaround Microsoft has suggested to return invalid for func7
        * Package, so return 2 elements package but only initialize elements
        * when acpi_index is supported and leave them uninitialized, which
        * leads elements to being Uninitialized ObjectType and should trip
        * Windows into discarding result as an unexpected and prevent setting
        * bogus 'PCI Label' on the device.
        */
       ifctx1 = aml_if(aml_lnot(aml_lor(
                    aml_equal(acpi_index, zero), aml_equal(acpi_index, not_supp)
                )));
       {
           aml_append(ifctx1, aml_store(acpi_index, aml_index(ret, zero)));
           /*
            * optional, if not impl. should return null string
            */
           aml_append(ifctx1, aml_store(aml_string("%s", ""),
                                        aml_index(ret, one)));
       }
       aml_append(ifctx, ifctx1);

       aml_append(ifctx, aml_return(ret));
    }
#

it seems like this is making an intentionally problematic acpi table to workaround a windows bug

#

this is such a rip

#

πŸ’” πŸ₯€

#

areeee yooooouuu kidddiiiing meeeeeee

#

i need to patch qemu πŸ’₯

#

what a rip

#

we switching to virtualbox after this one πŸ—£οΈ

steel herald
#

Nah that's not it boss

pearl kindle
vagrant cedar
eager yew
# steel herald Nah that's not it boss

I'm perplexed as to why this is only prevalent on recent versions and specifically the recent macos version

I shall find out though

very confusing

if it's a bug with the allocator or something then one of my other tests would've surely caught it and I checked and nothing ever overwrites the acpi data stuff

#

I don't see any other changes to qemu acpi besides that thing recently

#

πŸ’₯

steel herald
#

yeah it most likely is an allocator bug

eager yew
#

it's very odd how this is a recent bug and didn't occur prior to this though

steel herald
#

yeah probably

#

idk why it only reproduces there

#

its possible it reproduces always but doesnt cause noticable problems

eager yew
steel herald
#

im not sure its anything to do with the memory map

eager yew
#

maybe their acpi table change moved stuff around and that caused the problem

steel herald
#

u allocate with the heap allocator right

eager yew
#

ya

steel herald
#

id look there

eager yew
#

i have a region of virtual memory that is used for my kernel slab allocator and I never see the acpi addresses get mapped there so I don't think it gets overwritten by that

molten night
steel herald
#

u most likely trash method code or something

eager yew
steel herald
#

when does uacpi error out exactly

eager yew
molten night
#

I've been bitten by it before, so I'm warning you might be looking at the wrong tree

eager yew
#

I think the table name is gone

steel herald
#

this should be sure easy to debug

#

just put a watchpoint

#

and see who overwrites the address

eager yew
#

watchpoint at what address tho

#

do i find what address is causing this problem

steel herald
#

u said the table name is gone

eager yew
#

well I think it's gone since it says in \()

steel herald
#

no lol

eager yew
#

oh ok

steel herald
#

this just means root-level code

eager yew
#

ohh right

#

this is with -M q35, if I remove -M q35, I get this

>> UACPI ERROR: unable to lookup named object 'οΏ½οΏ½οΏ½' within (or above) scope '\_SB_.PCI0': invalid AML name string

>> UACPI ERROR: aborting method invocation due to previous error: invalid AML name string

>> UACPI ERROR:     #0 in \()```
steel herald
#

so basically start by opening up gdb and putting a breakpoint to the place in interpreter.c that prints this

#

then check the aml_pc at that location

eager yew
steel herald
#

from that u can compute the address

#

in the DSDT

#

and put a watchpoint there

eager yew
#
Returning invalid namestring, cursor is 0xfffff00002821f7d
>> UACPI ERROR: unable to lookup named object 'οΏ½οΏ½οΏ½' within (or above) scope '\_SB_.PCI0': invalid AML name string```
#

found that thing

steel herald
#

yep, just watchpoint that thing

eager yew
#

hmmm watchpoint is making things slow down to a halt and then qemu becomes unresponsive

#

odd

#

doing a breakpoint and then running to the breakpoint before doing the watchpoint does the same

#

πŸ’₯

#

yea it just dies, rip

#

had to sigkill it

maybe this is macos being funny, once i get home and try on linux then i'll see if the same behavior happens

qemu just dies here with the watchpoint

steel herald
#

strange

#

maybe only enable the watchpoint right before calling uacpi_namespace_load?

#

and dump the data at that pointer before calling it

#

to be sure its not already garbage

eager yew
#
    // IDT
    idt_init();

    // Early device init
    k_printf("uacpi init\n");
    uacpi_init(rsdp_request.response->address);```

so i have this code, and i break right after idt_init, it runs right up to there with no issue, and i set the watchpoint on the address and `continue` and then it just dies
steel herald
#

just do it later

#

before uacpi_namespace_load

eager yew
#

anyway back to the hugepage allocator, I think I will provide nice interfaces for allocating hugepages that are entirely untracked in the main allocator

this way certain subsystems can essentially keep small chains of hugepages for "mini allocators" and it would probably make the lock contention significantly lower and also improve performance because those subsystems may only ever need single page allocations

#

probably just some simple ways to make a

struct hugepage_arena {
    struct list_head hugepages;
};``` and then just some way to add and remove and allocate from an arena
#

maybe this will make things happier idk I'll try it out

eager yew
#

I kinda realized that my explicit hugepage state tracking of partial, used, or free is entirely unnecessary (I keep track of the number of 4kb pages used per hugepage) so I'll probably swap that field out for something like a set of bitflags

#

maybe stuff like pinning hugepages to cores so they aren't migrated under memory pressure or something

dunno I'll think of something

#

I might add an interface for hugepage allocator hints or something

for example if you are unmounting a filesystem, a massive amount of pages are gonna be freed

so you could potentially hint to the hugepage allocator about this and it would do stuff like increase the size of the per core minheaps to avoid doing that during all of the frees or whatever

idk πŸ€ͺ

#

mallocplusai

#

hmmm if I'm introducing independently creatable untracked arenas I can probably also recycle them so once some subsystem is done with an arena it can give it back so I reduce calls into the physical memory allocator and the virtual memory mapping stuff

eager yew
#

hugepage allocator allocation interface is complete

#

now I need the page freeing and then the arena management and arena recycling

eager yew
#

I will probably make a hugepage translation buffer with a few entries in it, so that when I free from a hugepage rather than doing a full rbt traversal (expensive) I can just check this buffer to map a page to a hugepage struct

#

we have tlb at home

eager yew
#

ok I might be getting distracted by theorem provers and formal verification, I've been taking a more in depth look into this stuff and it seems incredibly interesting

so I may forgor about this for a while but hopefully I can multitask and do a bit of both

#

such cool things

eager yew
#

I probably need an oom handler callback infrastructure sooon πŸ’₯

vagrant cedar
#

Just panic on OOM like I do trl

eager yew
eager yew
#

oops I forgot to add profiling conditional compilation, I'll probably do that and do things like add fields to my locks to track contention and stuff πŸ’₯

eager yew
#

aborting on allocation fail better tbh trl

eager yew
#

that initgraph DAG thing that menix does is looking awfully appealing rn....

#

eh it's not a problem I can just group the calls to whatever _init() functions there are

#

so like mem_init() instead of all that

#

it ok

eager yew
#

when vmm.c becomes a 20 thousand line file

round geyser
eager yew
#

efficiency

eager yew
#

I just remembered I had a filesystem layer and thus can introduce swapping to disk 😲😲

#

memory management subsystem boutta go hard

#

page table aging πŸ’”

#

meh I'm in 64 bit so I have a morbillion available bits in page tables

#

first thing's first we finish up the hugepage allocator and introduce arenas that you can dynamically manage and use different allocation techniques (slab, buddy, bump, bitmap) for each page in each arena

#

then we do oom handling and add profiling in places

#

then fancy swap stuff

#

πŸ’₯

eager yew
#

diminishing returns after that

#

can use the rest of the bits for crypto mining πŸ˜ƒ

eager yew
#

C polymorphism πŸ₯΄

#

kinda ugly to do polymorphic code in C but it's alright I guess

#

bit of switch case/LUT never hurt anyone πŸ€ͺ

round geyser
eager yew
# eager yew I believe I only need like 2 bits for this though

ok if i rember, the way the clock works is that i keep track of all swappable pages somewhere and under memory pressure i start the clock to check if the A bit is set (and clear it if it is), and then if I encounter some page without the A bit set I move it to an inactive page list and that list eventually gets swapped to disk or something

that would be the most basic impl

and then i would probably use available pte bits as a counter to indicate access recency

#

πŸ’₯

#

i shall go do reading on this because i forgor

eager yew
#

nice my allocator can allocate 1gb in 7ms

#

fast enough for me

eager yew
#

oh yeah the filesystem integration test is finally at one singular millisecond

#

I am not gonna bother with making it faster I think

#

it started at almost 100ms I think

#

so that's cool

eager yew
#

i got distracted with cpu stuff so i will be on hiatus to probably start a project implementing risc v

#

i promise i am not marvin in disguise

eager yew
#

technically can be emulated ye

#

(I will be emulating it most times since I don't wanna have to constantly be around an fpga to work on this)

eager yew
#

looking into page LRU clock algorithm research to see what's the most optimal way to go and do this

#

I thinks I saw multics have something about this

#

debug duck 3d resin print πŸ˜ƒ

#

courtesy of a lab I got to work in

#

they had a bunch of extra resin that had to be used (otherwise it hardens and bad things happen) so I made the duck

#

you quack me up πŸ¦†

eager yew
#

hmmm i am running into the little pickle of how to handle a mid-page-swapout write operation

I think what I can do is set the page to read-only at the start of it being swapped so any writes trigger a fault that i handle

eager yew
#

how come

stuck nexus
#

The page should have been invalidated in all address spaces by the time you're writing it out

eager yew
#

ohhh ok so i first invalidate and then write it out

so then any mid-swapout faults would just wait for the write to finish before reading it back from disk?

#

or what

stuck nexus
#

You could but what I did is just let the page out finish and then when it's done I notice the page was written to while it was being paged out

#

At which point I free the backing in the pagefile because it's obviously not valid anymore

eager yew
stuck nexus
#

Think so

eager yew
#

ok sounds good

stuck nexus
#

What's your concern

eager yew
# stuck nexus What's your concern

well let's say i have this scenario

page is currently in the swap-queue, and is actually getting swapped to disk

then, a write to that page comes in during this portion of time

what do I do?

is the proper order of things to

mark page as being swapped out -> mark page as RO everywhere -> begin swapping it to disk -> unmap page (set it as not present) ->deallocate page

this way if I catch that fault (upon write), I let the swap operation finish, but then make sure to mark that entry in the swap as invalid, and then map the page back in since the page is still allocated in memory?

stuck nexus
#

I think you are conflating eviction with page out

eager yew
#

so would this be the proper way to do that?

#

or nah

#

hmm i shall check what the terms actually mean lol

eager yew
#

and then eviction can be that, but it can also be just deallocating a page without any write to disk if said page is not dirty

#

so this would be page out then

eager yew
#

had to fly on airplane back home so no work today but i did read many cool multics stuff on airplane

#

riveting

eager yew
#

how do people live with -O3 compile times lol they're noticably slower

#

o well

slim raft
steel herald
#

If u do O3 you're probably not developing stuff

#

So u only compile once

slim raft
#

I used to use gentoo with O3

#

πŸ’”

eager yew
slim raft
eager yew
#

yet

#

im pretty sure the optimizations between O2 and O3 are very very marginal

slim raft
#

it could be yet and it could also been mild unnoticeable ubs under the hood

eager yew
#

anyway time to read MS docs about APCs

#

I should have all the necessary infra to do them

#

πŸ€ͺ πŸ’₯ πŸ’» time

#

Antigen Presenting Cells

#

seems like NT has passive, apc, dispatch, and device isr irqls

#

neat

#

so i think I'd just do a queue per thread with irql raise and lower functions and each core has an irql field in the struct

#

i remember minty a had a big comment about these

#

might go and find it

#

lazy apcs when they meet productive apcs

stuck nexus
#

so dont read my thing and think it applies to NT

eager yew
#

thank

eager yew
#

oh yeah that uacpi thing went away for some reason after i switched to my new page allocator

#

πŸ’₯

#

right ok so next order of priorities would be

  • apcs (I think they are fun and cool)
  • pager and stuff
  • implement all that scheduler stuff i was talkin bout (I think i got it figured out)
#

woah that guy is really spherical

#

my source tree with full depth git clone is 4.3mb already.... πŸ’”

#

wait my binary is smaller than my sources that's so awesome

#

by like 1/4th too

#

woah

eager yew
#

πŸ“Ÿ

eager yew
#

pager time today πŸ“Ÿ

#

actually making my other allocators faster is probably more optimal, I saw that linux essentially makes lists of slabs in their slab allocator for cross core frees

#

probably gonna do a similar "global tree, per core lists" approach

placid vessel
eager yew
#

or is that planned for the future

placid vessel
#

what that mean

#

paging can mean a ton of things depending on who you ask

eager yew
placid vessel
#

kinda

eager yew
#

how does it kinda have that

placid vessel
#

user programs have it

eager yew
#

oh yes I see it in code

#

great stuff

placid vessel
#

it's not exactly complicated

#

you just record your own kind of page tables

#

then on page fault you fill the page in

eager yew
#

rmap lore

#

sounds great

#

nsg was talking about a fully demand paged kernel which sounds interesting and problematic

#

demand paged interrupt stacks trl

placid vessel
#

yeah no that's not happening

#

nobody does that

eager yew
#

0% in RAM

eager yew
#

may have gotten distracted and not worked on allocators at all

#

apcs are pretty cool

#

I get to WaitForSingleObjects now

#

wait i forgot an init function

#

rookie mistake

#

all good 😎

eager yew
#

I think I might add on_destroy APCs that run when a thread is destroyed, maybe some things will have use for it

#

yeah I think doing that could make a lot of stuff a lot cleaner hmmmm

steel herald
#

How do your apcs work?

eager yew
# steel herald How do your apcs work?

same as most other APCs, they execute when the IRQL drops to PASSIVE and you can optionally choose to mask execution of certain types of APCs in some code segments

right now I just have kernel APCs and special kernel APCs, I'll probably introduce on_destroy APCs that run specifically when a thread is destroyed, so rather than manually checking in a bunch of different subsystems to clean things up, I just walk the chain of on_destroy functions

#

oh right the proper way of phrasing the first part is "When the IRQL drops below APC_LEVEL"

#

lol I only have PASSIVE below that rn

#

I might start using CR8 soon

#
enum irql {
    IRQL_PASSIVE_LEVEL = 0,
    IRQL_APC_LEVEL = 1,
    IRQL_DISPATCH_LEVEL = 2,
    IRQL_DEVICE_LEVEL = 3,
    IRQL_HIGH_LEVEL = 4
};
``` astounding gameplay
eager yew
#

just realized that because I have the behavior that makes the scheduler go tickless if there is only one thread, I may need to have a mechanism where I go

"If the target core is at an IRQL below APC_LEVEL but it has its tick disabled, I will IPI it to force the reschedule and run the APC"

#

coz when it's tickless there is no rescheduling happening so no apc would run

eager yew
#
/* Poke the target core if there is no preemption on it
 * because we need the thread to reschedule to run its APC */
static inline void maybe_force_reschedule(struct thread *t) {
    struct scheduler *target = global.schedulers[t->curr_core];
    struct core *core = global.cores[t->curr_core];
    enum thread_prio_class class = prio_class_of(t->perceived_prio);

    if (!target->timeslice_enabled &&
        core->current_irql == IRQL_PASSIVE_LEVEL &&
        class != THREAD_PRIO_CLASS_RT)
        scheduler_force_resched(target);
}
``` astounding
#

oh dear wait I need to add refcounts and a proper full lock to the threads since this can race kind of badly

#

whoopsies

#

πŸ’₯

eager yew
#

bro thinks he's mintia

#

πŸ€ͺ

eager yew
#

πŸ’₯

#

i wonder why mintia doesnt split up the logic into smaller reusable chunks, idk it feels like a lot of stuff is duplicated

#

maybe jackal inlining is suboptimal or doesnt exist

stuck nexus
#

Wdym duplated

eager yew
# stuck nexus Wdym duplated

it just seems like logic repeats itself, like this snippet here

    // Add the APC to the list.

    RtlInsertAtTailList (
        &thread^.LapcListHead, // head
        &apc^.Entry, // entry
    )

    thread^.PendingEventsSet |= KI_THREAD_PENDING_LAPC

    apc^.Enqueued = TRUE

    apc^.Context1 = context1
    apc^.Context2 = context2```

exists in a bunch of places, like

```rs
    RtlInsertAtTailList (
        &thread^.UapcListHead, // head
        &apc^.Entry, // entry
    )

    thread^.PendingEventsSet |= KI_THREAD_PENDING_UAPC

    apc^.Enqueued = TRUE

    apc^.Context1 = context1
    apc^.Context2 = context2```

and

```rs
    // Add the APC to the list.

    RtlInsertAtTailList (
        &thread^.KapcListHead, // head
        &apc^.Entry, // entry
    )

    thread^.PendingEventsSet |= KI_THREAD_PENDING_KAPC

    apc^.Enqueued = TRUE

    apc^.Context1 = context1
    apc^.Context2 = context2

it's not a big deal i just found it curious that these kinds of things dont have their own functions

#

i didnt see any inline keyword in jackal

stuck nexus
#

I mean

#

I would consider it overkill to turn such small common sections into a macro

#

or other thing

eager yew
#

ok understandable, that would make sense for a lang without inline

stuck nexus
#

Even if it did

#

I probably wouldn't do that there

stuck nexus
placid vessel
stuck nexus
placid vessel
#

but like

#

i wouldn't even know that this exists

severe abyss
#

wdym

#

ah like after thread_acquire?

#

or am i missing something

stuck nexus
#

we've been talking about it for literally 4 years

placid vessel
#

I've only been here for one

stuck nexus
#

inchresting

placid vessel
#

same with gummi lol

twin eagle
#

will is actually an nt kernel engineer trolling the osdev community I can see behind the mask

stuck nexus
eager yew
#

these will be pretty useful once I start having more things that are bound to thread lifetimes so when I clean up a thread I don't need to insert a morbillion statements and can just walk a chain of function pointers

placid vessel
#

idk what that is even

eager yew
#

so if you have stuff that is bound to a thread it is very convenient

#

like let's say you're waking some threads up from an interrupt but need them to do some work, you can enqueue APCs onto them and they will execute the APCs once it is safe

eager yew
# placid vessel what stuff tho

if you decide to get fancy and do something like jemalloc where each thread has its own arena, you can enqueue the arena destructor as an on_destroy APC so that rather than hardcoding the arena as a field in the thread you can have it just be destroyed via an APC

#

this way if you have a thread that never does an alloc that function is never enqueued as an APC

#

or if you have worker threads with dynamically allocated fields you won't need to track those in the thread and can just use an APC to clean it up when the worker thread goes bye bye

round geyser
eager yew
#

how would it race if I didn't do that

#

this is all entirely possible without APCs I just think that they make things more elegant lol

round geyser
#

Ohhhh I misread what you said

eager yew
#

I think I will use the on_destroy APCs for worker thread cleanup since those are spawned and destroyed on demand

#

anyway i still dont feel like doing an allocator rewrite for the slab and buddy allocator to make it per-core and parallelized lol, I already recently rewrote my page allocator (hugepage allocator) to be parallelized and I am a little bored of allocators

I think I will go and finish the scheduler thing though because that was something I had planned, and already built out the infra for, so now all I need is proper activity classification, scheduling periods, and to migrate to the RBT with priorities 0-255

eager yew
#

kablooey

#

lol i once again had scheduler slowdowns due to MMIO for reading the timestamp in MS so I just cached an integer for that and now it is all good

severe abyss
eager yew
eager yew
eager yew
#

I think it's time to head back into ye old python interpreter to craft heuristics for this scheduler

#

probably gonna first start off with floating point stuff and migrate to integer

eager yew
#

some certified "We have floating point at home" code

eager yew
#

ok I will probably just have two trees, one for threads that are not done for the period and one for threads that are done, so when a new period starts i just swap the pointers

#

shrimple

eager yew
#
Thread activity metrics show block ratio 0, sleep ratio 0, run ratio 99, wake freq 1
Thread activity class is CPU BOUND
Priority in level is 1624528883, prio32_base is 1624378656, dynamic_delta is 150227
cached_prio32 is 1624528883, weight_fp is 1475543040, last_class_change_ms is 912``` hooray
#

numbers are working

steel herald
#

Which algo is this?

eager yew
#

they're just heuristics

#

for computing priorities and stuff

steel herald
#

Yeah but what is your scheduler algo

eager yew
#

and once i do all this

eager yew
#
> git commit -a
[main 6241a7b] [sched]: migrate to red black tree new scheduler
 22 files changed, 396 insertions(+), 222 deletions(-)
 create mode 100644 kernel/sch/internal.h``` all done
#

that was a lot of work I'ma take a break and write a yap about it later

#

had a blast though

#

spent 1 hour debugging issues where i forgot to set variables

#

truly incredible

round geyser
#

Nice bro

eager yew
#

wow the schedule loop still stayed under 3,000 clock cycles with the huge amount of extra logic I added

#

neat

#

next sched feature: cgroups

vagrant cedar
severe abyss
eager yew
#

cgroups (abbreviated from control groups) is a Linux kernel feature that limits, accounts for, and isolates the resource usage (CPU, memory, disk I/O, etc.) of a collection of processes.
Engineers at Google started the work on this feature in 2006 under the name "process containers". In late 2007, the nomenclature changed to "control groups" to ...

#

cool stuff

severe abyss
#

not much scheduler related tho?

eager yew
#

πŸ‘

severe abyss
#

cgroups are basically what windows nt calls job objects

#

i see

eager yew
#

jobjects

severe abyss
#

job-s

vagrant cedar
#

jobjs

severe abyss
vagrant cedar
#

sbeve

#

jojs

eager yew
vagrant cedar
#

sbeve noobjs

round geyser
eager yew
#

I am doing the Great And Wonderful Thing of adding conditional compilation for profiling flags and other stuff

#

truly a blast

#

linker script gonna bloat up real big fr

#

hot take cmake does not suck

#

cargo could never compare

twin escarp
#

ye I like CMake :3

eager yew
#

so useful

#

cargo absolutely could never

eager yew
twin escarp
eager yew
#

i wonder how old mintia did that cool profiling thing to record scheduler ticks (no I will not read old mintia df code)

stuck nexus
#

also wdym you dont want to read this

eager yew
#

the complexity is unmatched

steel herald
#

unreadable == complex KEKW

eager yew
round geyser
steel herald
#

Agreed

#

Cmake is pretty damn good

molten night
#

It suck the least out of all build systems ive used

eager yew
#

heard some good reviews about it

slim raft
molten night
# eager yew how is meson

Absolutely no idea, heard it addressed some issues with cmake but you wouldn't feel the effect until your cmake becomes way more bloated

eager yew
molten night
#

The ancient tombs must not be disturbed

eager yew
#

I think I will name the scheduler CATS for the

CATS Adaptive Timesharing Scheduler

eager yew
#

may be busy soon because school in a few weeks

#

probably doing allocator + memory management revamp soon, including the pager πŸ˜ƒ

#

then I'll move to filesystems and redo all that + proper page cache

#

might do networking afterwards or finish the xhci thing

#

then I'm probably set to do some syscall implementations, maybe start working on userland interfaces with some subsystems

#

I may dabble in userspace but idk

eager yew
# round geyser Awesome stuff

this will be AFTER I do all the other stuff so I'm not getting to userspace running on a UP system that has a 500mb RAMdisk and a tmpfs and hopes and dreams

#

πŸ’₯

round geyser
#

Right now I’m working on syscalls

#

I’ve finished my scheduler for the most part

eager yew
round geyser
#

Should be ret

eager yew
#

do you test your code

round geyser
eager yew
round geyser
#

It just does. Other kernels do it too

#

But yes, it should be ret

eager yew
#

are you tying scheduling to timer interrupts?

round geyser
#

I was, but now that that is changed, I don’t need iret

eager yew
#

ok then that would be why it was working, understandable

round geyser
#

Yeah lol it was set up weird before

#

I’m fixing it though

#

Yeah fixed it

placid vessel
eager yew
placid vessel
#

how

eager yew
#

i was assuming that this wasnt from interrupt context

eager yew
#

or is it different in 32 bit

placid vessel
#

yeah iret would need the rip, cs, rflags, rsp and ss

eager yew
#

As with a real-address mode interrupt return, the IRET instruction pops the return instruction pointer, return code segment selector, and EFLAGS image from the stack to the EIP, CS, and EFLAGS registers, respectively, and then resumes execution of the interrupted program or procedure.

ya

#

so if you just call into a function iret would not be happy

#

but it would work fine there since the task switches were tied to interrupts

#

i assumed they werent lol

eager yew
#

I have just realized I can make the on_destroy APC idea more generic by having on-event APCs

like my DPC worker threads are currently pinned to the core that they spawn on, because there is extra logic to migrate a DPC worker thread from one core to another, due to internal structures that need to be changed, and I haven't implemented that yet

I don't really wanna hardcode that in the scheduler since that seems like it would get quite unwieldly quite fast as I accumulate more and more of these things, so maybe I'll do something like

enum apc_event { 
    APC_EVENT_THREAD_MIGRATION,    
    APC_EVENT_THREAD_DESTROY, 
    APC_EVENT_COUNT,
    /* ... */ 
};```

and give each thread a

```c
struct apc *on_event_apcs[APC_EVENT_COUNT];```
eager yew
#

i wonder how i can keep threads pinned to the open thread list so they dont vanish after inactivity

#

keeps happening with some threads

#

o well

eager yew
#

I have realized that I need to add work pushing where busy cores push their threads onto idle cores to get them to run them

#

rookie mistake

#

or I can just make the idle thread try steals in the idle loop but idk

#

actually I won't need to do work pushing I think I can just IPI the other idle cores and they'll enter schedule() and steal

#

I can probably just use a simple atomic bitmap for marking cores as idle/running and if I detect more than 1 available thread to run + an idle core I just IPI it to try and get it to take the thread away

eager yew
#

ok actually nevermind that is Big Dumb, I should probably come up with a way to represent processor topology in a hierarchical manner so that things like "hyper threads" that share a pipeline are picked first, then cores in the same numa node (if available), before a full CPU scan

#

and whatever layers I forgot

severe abyss
#

maybe its be better to spread the load avoiding smt sibling threads when there are free cores

#

so they dont compete

eager yew
#

maybe but it's not a terribly huge deal

eager yew
#

anyway yeah I think I don't need a tree to represent CPU topology lol

#

something like a

enum topo_level { TL_SMT, TL_CORE, TL_LLC, TL_PACKAGE, TL_NUMA, TL_MACHINE, TL_MAX };

and a

struct {
    struct topo_node *level[TL_MAX];
    uint16_t          count[TL_MAX];
} topology;
``` perhaps
#

i think u16 is fine here since x86 has a max of 2^16 cores supported

#

lol what a silly thing to worry about

#

then i put some core structs and whatever else in each topo node πŸ’₯

eager yew
#

ok so I've been kinda busy lowk but I'll be figuring out how to represent processor topology in software (and parsing it from hardware) and stop doing full cpu scans πŸ’₯

pearl kindle
#

full cpu scans?

eager yew
#

that doesn't scale well if you have many cores

#

and it's more optimal to scan from "better" cores to "worse" cores relative to your core

#

like first try SMT siblings before going to other numa nodes or whatever

eager yew
#

ok just a note to self here:

if/when I do power management modes (pmms trl), I'll need to figure out a way to get all subsystems to "pile up their work" on a few cores if there is a lot of stuff going on so the other cores enter their idle threads and conserve power

#

like with my scheduler I'd probably wanna shove everything on the least amount of cores necessary to run all the threads optimally and then set some mode to tell the scheduler to not perform logic regarding rebalancing until the mode is disabled

eager yew
#

just a scheduler shenanigan

#

ok so for my CPU packing logic, I'll first obviously need to make a topology aware representation of all cores (duh), and then I'll need a way to figure out which "active" cores and which "victim" cores I want, and have some tunable knob

so at a low cpu packing value, I would just avoid core 15 and then run everything on cores 0-14, whereas at a higher value I might consolidate things to only cores 0-3

and then I could probably also make my scheduler period computation and timeslice distribution aware of this, so that as the cpu packing value increases, the timeslices and scheduling period lengths increase as well

#

blah blah blah blah

eager yew
#

documenting le scheduler rn, been busy πŸ’₯

eager yew
#

working on trying to see if I can get panic handler hooks working to have tests that are marked as SHOULD_PANIC

#

void (*panic_handler)(char *file, size_t line, char *function, char *message); maybe something like that as a global handler

#

"we have rust at home"

#

I'll probably just wanna split stuff into k_panic and k_bug for that differentiation between recoverable/unrecoverable problems

#

prob can use setjmp/longjmp

eager yew
#

parsing cpu topology and representing it in software today

eager yew
#

my memory access is non uniform

leaden magnet
eager yew
# leaden magnet whats the issue with writing a numa aware allocator?

well you'd probably want other subsystems to be NUMA aware too (scheduler in particular) so that the allocator being NUMA aware also works

but the other troubles are

  1. figuring out the ideal node to allocate from if this node's address range is exhausted
  2. structures in the allocator need to balance locality with availability so you don't run out of memory on the local node too fast
  3. cross-core frees and load balancing
  4. allocator interfaces need to be more complex (you can't just pass in size) as you'll need to know what nodes you might be allocating from, and whether to interleave between nodes, etc.
#

a NUMA aware allocator can't optimally perform if it uses the simple "Flat Memory Model" that we are all oh so familiar with

leaden magnet
#

so you are looking at different "distances" given a node?

eager yew
#

and you parse ACPI tables to essentially figure out "distances"

#

higher distance -> higher latency

#
> numactl --hardware
available: 4 nodes (0-3)
node 0 cpus: 0 1 2 3
node 0 size: 983 MB
node 0 free: 852 MB
node 1 cpus: 4 5 6 7
node 1 size: 1007 MB
node 1 free: 923 MB
node 2 cpus: 8 9 10 11
node 2 size: 943 MB
node 2 free: 812 MB
node 3 cpus: 12 13 14 15
node 3 size: 1007 MB
node 3 free: 916 MB
node distances:
node   0   1   2   3 
  0:  10  15  20  20 
  1:  15  10  20  20 
  2:  20  20  10  15 
  3:  20  20  15  10 ```
#

exampl

leaden magnet
#

isn't it just duplicating the allocator state so you have a array of states[] indexed by the node

eager yew
#

if core 5 of node 1 wants to free memory from core 0 of node 0, what do you do?

#

a common approach is to have local lists of objects to free so when you call free() you drain that list

#

and you would add whatever you're freeing to that other node/core's list

#

and also the trouble of running out of memory on the local node and balancing things so that you don't run out of memory too fast

leaden magnet
#

or take that nodes allocator lock?

eager yew
#

allocators like this don't have an "allocator lock", they would typically lock much more fine grained like with per-core states

leaden magnet
#

so you are implementing something similar to the slub with a per core slab?