1,379 karma · joined April 8, 2014
Even if one does assume a Shannon-perfect coding scheme, as the noise ratio gets greater the benefits of spreading a signal across a higher bandwidth fades. Furthermore, most coding schemes hit their maximum inefficiency as the signal to noise ratio decreases and messages start to be too garbled to be well decoded.
I’d additionally note that folks get near the Shannon noise limit _through_ ‘magic noise rejection’ (aka turbo and ldpc codes). It’s therefore not obvious that FM isn’t gaining clarity due to a noise rejection mechanic. The ‘capture effect’ is well described as an interference reducing mechanism.
Empirically, radio manufacturers who do produce sophisticated long range radio usually advertise a longer range when spreading available power across a narrower rather than wider bandwidth.
Essentially, if I pay you £15k for some services, you pay income tax on that £15k. If I buy you a car for £15k, taxman still wants £15k. Same with equity.
How it can work is that you can be granted shares and pay the taxes at time of granting (which for a founder is zero), but might not be nice for an employee.
You can also give an employee options, and this can get complicated (single or double vest).
But in general, for any equity instrument in a stock plan, you get charged income tax at one stage, then capital gains at a later stage, and you can trade off when you want to trigger each. In this case, employer has gone for a model where income tax is deferred as late as possible.
Next, work out where you want to be in terms of comp in a few years, rather than thinking of how to optimise the cash right now. For example, I'd stop worrying about your tax-free allowance gradually disappearing, and instead try to work out how to get it to all be gone. In 5 years, the person who makes £120k is £40k better off than the person who makes £100k, after tax. That... sounds worth it. And it's usually easier for the person who's getting paid £120k to get paid £130k than it is for the person who's getting paid £100k. This is to say, having high tax brackets is a benefit, not a curse.
And then, it's probably worth noting - this isn't directly their money, especially if they're looking to sell. It's probably worth having the conversation of like, 'what would I need to do in order to justify £100k/year?'. Or, alternatively, negotiating on the vesting of your stock, since that's effectively free. If they think the company is going to be sold in the next few years, that's a relatively small giveaway for you. If the company's grown a lot in four years, it's unlikely a significant increase in stock is on the table.
Don't overestimate how long it'd take a good new person to catch up. I've rarely seen a role where a new person can't be effective within 6 months.
1. Scaling. You want to reap the rewards of someone else investing billions, and while billions of ICE engines are built every year, most of them are much bigger than 50cc. 2. Tolerances, as you say. I know for example that jet engines have low efficiency at small sizes due to efficiency being driven by the gaps between certain rotating parts, which are relatively larger. 3. Certain parts that need miniaturisation are more expensive on smaller engines. For example, a 50cc would typically have a carburettor, a bigger engine fuel injection. A fuel injector would be significantly larger per unit. 4. Some parts are just harder to miniaturise. For example, small turbochargers have to work harder and at much higher RPMs to achieve the same boost due to area scaling quadratically with diameter.
Under 5kg of batteries, engines basically can't compete. The smallest viable petrol engines (you want engines made in large quantities) are around 4kg and need fuel, and so you end up in a situation in which 4kg of engine and 1kg of fuel is as useful as 5kg of batteries (for motors of that size), but every subsequent 1kg of fuel is then also as useful as 5kg of batteries. But you can't really drop this down much, as a 1kg engine is much less useful than 1kg of batteries, and a drone with 5kg of batteries is really a very large drone.
Drones are additionally typically very small and light, with mass at an absolute premium. A typical quadcopter will weigh under a kilogram and have maybe 200g of batteries for 20-30 minutes endurance. A drone with a 2.5m wingspan will typically have room for maybe 1-2kg of extra payload, and an engine will not fit into the battery slot.
Furthermore, they are extremely sensitive to weight balance issues.
This is to say, once you're in the world where you want chemical fuel, you might as well design a drone for it, rather than trying to retrofit. The mass of retrofitting will mess up your prior drone design, and petrol changes the dynamics of what you're trying to do enough that you might as well just do it all differently.
Essentially, if you're making a 1-10kg drone, you want battery. If you're making a 10-20kg drone, you might want battery, you might want petrol. Above 20kg, you probably want petrol.
Assurance is a complex topic, and any safety critical device should have a carefully thought through architecture and rigorous testing program which minimises the risk of incidents. It therefore seems scarcely relevant here, beyond the fact that a well defined delivery system should be able to handle multiple human errors during implementation without leading to crucial failure modes occuring.
Lots of the time you understand the problem, but the problem is repetitive. Parsing a weird file format might well be that. Beyond that, you have solutions that are easily checked. For example, if I ask ChatGPT to optimise an algorithm for a certain CPU cache, I can easily read whether it did that. And then, there are parts of a software job that are crucial and subtle, and parts that are not.
As a practitioner, traditionally that leads to a shift in the focus and speed with which you approach a task - some pieces of code are 100 lines that took you 2 weeks to get to and were hard fought, some are 2000 lines which you wrote in a day.
Lastly, so much of solid software is being able to understand a probably unfamiliar domain, and ChatGPT can be a great buddy in terms of gaining problem context, finding the limits of your own understanding.
I don't use co-pilot like things, but I've found ChatGPT to be a massive enabler in terms of being able to be productive in unfamiliar problem-spaces.
If your job is to make an accurate parser for it, probably you want to hand code it. If your job is to make sense of the data the customer has provided you with, this is merely an impediment to your actual job, and ChatGPT has you covered. Yes, there'll be mistakes. But ChatGPT can do in a few seconds what'd take you hours.
E.g.
for (int i = 0; i < 500; i++) {
newVirtualThread(() -> synchronized (new Object()) {
Thread.sleep(100_000);
});
}
will blow up your JVM (modulo some compensation mechanisms that work definitely kinda) and that's odd.IMO the compound thing is what makes it be nasty. E.g. you have a function `doSomething` which does some RPC, and that's all nicely non-blocking. But someone called map.computeIfAbsent(x, k -> doSomething(k)), and that uses synchronized on the inside so now your non-blocking API calls all magically became blocking, no further action required.
Java instead did a big thing where they made all the primitives work fine in both cases with one API, something which is honestly really hard and really reflects the level of thought put into modern Java features. But there's a long tail of stuff that's still getting cleaned up (e.g. various weird I/O apis), and honestly I think it _is_ weird that an actual language keyword made it into the long tail.
It's extra fun that it's actually quite hard to hit performance problems as a result of this, as the JVM will actually detect that it's getting to this problem and boot up threads to compensate.
Like, it makes sense that when you synchronized on an object, there's room for contention. It seems weird that synchronizing on an _uncontended_ object can cause contention. But that's what this is. The behaviour is that you have target numCores carrier threads, and if someone synchronizes on an object and then does a non-blocking sleep, it's now blocking, because synchronizing upgraded the non-blocking I/O to blocking.
So basically when you hit this issue, it's because not only has the bad thing been happening, it's also been happening badly enough that all the compensation mechanisms have failed.
It's just weird that a whole language level keyword behaves this badly.
There of course are things like ErrorProne that statically check that you unlocked your lock, but there's still bugs possible.
For example, Rust lifetimes (this is also the case in C++ afaik) can be used to suitably scope the lifetimes of mutexes, to have temporary folders which are deleted when they go out of scope, to require that a connection pool is destroyed _after_ the last connection inside it is returned, etc, etc.
Mostly, garbage collected language do a bad job of cleaning up objects which refer to resources held elsewhere. Java had persistent issues with direct ByteBuffers (which were wrappers around malloc (but not free!)). Locks are easily held too long. File handles are easily left open. And depending on your GC settings, that file descriptor that's holding a 10GB file around may not get cleaned up for hours.
Refcounted languages can be somewhat better, but they don't avoid the bug, they just mitigate the effects.
There were very many important changes in the meantime over that timeframe, but generics and lambdas fundamentally changed how you use the language - Java 4 is not the same language as 5, same between 7 and 8. This is not the case for the 6 and 7 releases.
The world emissions per capita are presently around 5T per year, per capita. The world has 5 billion hectares (out of 13B total) of agricultural land in general, overall (and generally if land _could_ be used for agriculture it _is_ used for agriculture), so generally, there's not a tonne of space to do lots of carbon sequestering quickly with agriculture, especially as you'd need to move the carbon you've created somewhere else.
The moral is that if you can ever get sequestering carbon down such that you can sequester 1 tonne of carbon for 20MWh power, you're close to a major winner, at least in all the deserts where you clearly can't grow bamboo but can grow solar, because at that point your cost of operations is just cost of infra. That startup thinks it can get down to around 1MWh/tonne, which is comparatively awesome!
My conclusion (before getting to something super scientific) was that if you want to rely on trees and swamps for your carbon capture, you basically end up with massive geopolitical issues because you need to cover most of the world in trees and swamps, but most of the world's land is already used to grow food. Meanwhile, carbon capture can work in areas where land is not (as) valuable.
If they are able to get to $50/tonne, that implies 1MWh/tonne, so that's about 500 tonnes/year per hectare. That'd mean that if you covered arizona in solar panels, you'd be sequestering 1/5 of human carbon output. Whereas if you grew bamboo, you'd cover the contiguous US for the same output.
Do I believe them? No. But even 10x worse is cheap enough to change the world.
The better your competing offer, the better the negotiating position. And while Amazon hasn’t gotten more expensive per se, it’s certainly not gotten cheaper.
But ensuring some parallelism while maintaining thread safety is straightforward in many contexts - an uncontended mutex is close to zero overhead. Languages like Rust make it harder to struggle with some of the thornier issues (data races which cannot be simulated by stepping threads).
E.g. in Java a typical system looks like a thread per request with some shared underlying data structures like caches or connection pools. Relatively easy to use these safely, or to guard some shared object with a synchronized.
Likewise with parallelism - a lot of problems just boil down to ‘do a few map reduces’ and the parallelism is pretty trivial.
Obviously, concurrent systems are fiendish to reason through - but there are a lot of cases where the complexity can be side stepped. Doesn’t seem to stop people writing scary code on the daily though.
The other element which is a bit scary is that it's fairly rare these days for mass market companies to index deeply on tech which isn't available in public clouds, so until AWS supports this sort of thing, it's unlikely that many folks will target it. You can kind of see this with the Optane PDIMMs - they looked absolutely fantastic, but given you couldn't get them on any AWS instance there wasn't much point actually trying to use them outside of very specific applications - as a software engineer this hardware lets me build my software very differently and in a simpler way, but how can I possibly risk architecting based on that if it then cannot support a customer's cloud migration?
Obviously v different in HPC contexts.
And it should always be said - latency is very different between these. Memory latency still measured in nanoseconds, PCIe latency still measured in 10s of microseconds, about 3 orders of magnitude difference.
This has some cool use cases! For example, Microsoft SQL server can already use SGX to implement additional data security. A user can run sql queries including pushdown filters on data the administrator of the server can never access, because certain columns of the data is encrypted and never held unencrypted in memory. If you're at a tech company and have ever worried about rogue administrators accessing the data of your users, these enclaves are great for that (in theory)!
Right now, people have to build their own transport layers, which interact with the attestation APIs. These folks are trying to build something that is as easy to set up as TLS.
A problem with all this tech is that to the extent it can be used to make business problems easier to solve, it makes it much harder to introspect what running software is doing, which from a software freedom perspective tends to raise hackles. My hope would be that in general, this is more used like 'corporate TLS interception' insofar as your personal device does not do it, but I'd expect that mobile device vendors use it before too long.
glibc shouldn’t be statically compiled in because it’s lgpl and so immediately infects your code if you do.
The zig linker is quite nice here because it lets you pick what glibc you want to be compatible with.
Example of fairly standard Cassandra bug (don't know if present on latest release, certainly was a year or two ago): When you add a new node to the cluster, it 'bootstraps', where it copies ~1/n the data from other nodes. When you are done bootstrapping, it's copied a bunch of data from other nodes, but the other nodes still contain that data. You then run 'cleanups' on the other nodes to remove the (now stale and unusable) data so as to get your disk space back.
If you accidentally run a cleanup on the new node as it is being bootstrapped, it will succeed, you will delete all the data that's been copied over so far, and Cassandra will _not_ terminate the bootstrap. Everything will be green, but your new node will suddenly be using 0 disk space. When the bootstrap finishes, possibly days later, your cluster will be immediately corrupted due to violated replication guarantees - but only on data that hasn't been read or written over that period, because if it was written it'll be re-replicated, and if it was read Cassandra will silently repair at this time. Repairs resolve the issue, but if you've made this mistake due to scripting, if you get unlucky it's possible to just delete all replicas of some data between repairs.
Example of other Cassandra bug (again, might be outdated): Cassandra nodes identify themselves on startups with IPs, and the owned token ranges are not persisted, they're streamed from other nodes in the cluster. If you've deployed your Cassandra in K8s and you reboot multiple nodes in one go and they swap IPs upon reboot, you may now find yourself in a split brain situation in which nodes magically forget they own certain data ranges and think they own each others data (or maybe it's that the nodes still think they own the right ranges but other nodes think they own the wrong ranges). Wasn't close enough to fully debug that one.
It's a mess. Would seek to avoid problem spaces where I might need to use it again, though if by chance ended up in a space where it made sense, probably wouldn't avoid the tech.