When your computer is started, and the first bit of software starts running on it, that software knows what class of processor it is running on - it knows that because it has been compiled for a certain class of processor, and if your computer had a different kind of processor the software would immediately crash, so the fact that the software is running proves what kind of processor it is running on.
Each class of processor comes with concrete processors that each behave slightly different. These differences are documented and can be used to determine what exact kind of processor there is. For example, the documention for x86 processors might say "on this group of processors, bit 12 of some condition code register is always zero, so after trying to set this bit to one it, will still be read as zero. On this other group of processor, the bit will be read as one after setting it to one". With that knowledge, the software can determine exactly which kind of processor there is.
And then, the software developers check their manuals again, and they read things like "this kind of processor always has 16KB of L1 data cache. For that kind of processor, you execute a certain instruction, and after that instruction, register two will contain the size of the L1 data cache in bytes". That's just an example, but these things will be documented, and the software developers use them to find out anything they want to know.
Now when you say "cache size", things are more complicated nowadays (they always are). As an example, an Intel server might have two sockets containing two separate physical chips, each chip might contain 8 cores, and each core might support two virtual cores. In that case, you might get the knowledge "there is 64 Kbyte of L1 cache, shared between two virtual cores, 256 KByte of L2 cache, shared between two real cores, and 12 MB of L3 cache, shared between all cores in one physical chip". So your computer would have a total of 64 x 8 x 2 KByte of L1 cache, 256 x 4 x 2 KByte of L2 cache, and 12 MByte x 2 of L3 cache, but each processor thread only sees a limited amount of that, and may have to share that cache with other processor threads.