Hacker News new | past | comments | ask | show | jobs | submit | suresk's comments login

Kind of funny, I was just looking at adding similar functionality to an internal Chrome plugin I built because we struggle to get enough useful info in bug reports (being able to look at the HAR, in particular, is useful, but difficult to get users to do correctly).

Two questions -

1) Any way to customize which headers/cookies get scrubbed?

2) Is there a way to get something like the lower-level export you can get by going to chrome://net-export/?


Ha, that’s cool!

We don’t have a way to customize that yet but we absolutely need to build that

And yes! Network logs get captured and added to the bug report automatically and we have copy as curl too so you can retry the request locally


This would have been so useful this past week while we debugged something that ended up being a weird combo of Comcast/Cloudflare/http3 - only some people could reliably reproduce it and it was a lot to coach them through all the steps.

Being able to redact a few values would be really important for us (I just wrote Python scripts to clean the har files up), but I’m going to play around with it this weekend.


GAR - Generation-Augmented Retrieval?

I've actually had some success with getting ChatGPT to create Redshift queries based on user text and then I can run them and render results, which has some interesting use-cases.

Max calls out the biggest problem with using something like ChatGPT in a search flow - it is way too slow. I've talked to a lot of people wondering if we can just shove a catalog at ChatGPT and have it magically do a really good job of search, and token limits + latency are two pretty hard stops there (plus I think it would be generally a worse experience in many cases).

What I'm trying to look at now is how LLMs can be used to make documents better suited for search by pulling out useful metadata, summarizing related content, etc. Things that can be done at index time instead of search time, so the latency requirements are less of an issue.


Yeah, I think any bytecode interpreter ends up with a giant switch in the critical path at some point :)

Around the time that change was made to Go, Andrew and I were looking at this and wondering how big of a performance hit it was and if there were a better way to structure that. I had a hunch that the compiler should be smart enough to not compile that as a switch/giant if block, and a quick trip to a disassembler showed it using binary search. This commit: https://github.com/golang/go/commit/1ba96d8c0909eca59e28c048... added the jump table and has some nice analysis on where it makes sense to do binary search vs jump tables.

As far as I can tell, with certain restrictions (that are fine in this case), it is pretty reliable at optimizing giant if/else blocks and switches.


Can you elaborate more on this?

> E.g. Haskell has an awesome concurrent GC that’d work like crap for Java, because it assumes tons of really short-lived, really small garbage and almost no mutation. The other way around is also bound to be problematic—I don’t know how the Scala people do it

I don't know a ton about Haskell's GC, but at surface level it seems very similar to several of the JVM GC implementations - a generational GC with a concept of a nursery. Java GC is very heavily designed around the weak generational hypothesis (ie, most objects don't live long) and very much optimizes for short-lived object lifecycles, so most GC implementations have at least a few nursery-type areas before anything gets to the main heap where GC is incredibly cheap, plus some stuff ends up getting allocated on the stack in some cases.

The only big difference is that in Haskell there are probably some optimizations you can do if most of your structures are immutable since nothing in an older generation can refer to something in the nursery. But it isn't super clear to me that alone makes a big enough difference?


One major simplification you can make is that due to purity, older values _never_ point to newer values. This means when doing generational GC, you don’t have to check for pointers from older generations into newer generations.


This feels wrong. Specifically, doesn't laziness bite you in this scenario? If I make a stream that is realized over GC runs, I would expect that a node in an old generation could point to a realized data element from a newer generation. Why not?


It does: "Nevertheless, implicit mutation of heap objects is rife at runtime, thanks to the implementation of lazy evaluation (which, we admit, is somewhat ironic)." says <https://www.microsoft.com/en-us/research/wp-content/uploads/...>


It is kind of interesting to look at some of the differences in GC approach in the JVM vs Go - the different goals, different tradeoffs, different approaches, etc. Go's is definitely simpler in that there is a single implementation, it doesn't have nearly as many tuning knobs, and it is focused on one things vs the JVM GC implementations that give you a lot of control (whether that is good or not..) over tuning knobs and it is a pretty explicit goal to support the different GC-related use cases (ie, low-latency vs long-running jobs where you only care about throughput).

One of the things I really like about Go is that a lot of the designs and decisions, along with their rationales, are pretty well documented. Here are the GC docs, for example - https://go.dev/doc/gc-guide.

For example, Go doesn't move data on the heap around so to combat fragmentation, it breaks the heap up into a bunch of different arenas based on fixed sizes. So a 900 byte object goes into the 1K arena, etc. This wastes some heap space, but saves the overhead and complexity with moving data around.



Arenas are still experimental (as of go v1.21).


Sorry, I used the wrong terminology. They are called “spans” in Go’s GC. There are different sizes of spans that allocations end up in, which helps avoid fragmentation.


It's one of those things where you usually have to let profiling and other observations guide your approach. 99.9% of the time it doesn't really matter and the default behavior is fine. But I can think of a few times where this has been a big deal.

One in particular - I was profiling an application with low-latency needs and GC was taking up a ton of time. Mission control showed tons of allocations of arrays - at one point it was creating a bunch of lists in a loop and adding stuff to them, which triggered creating a new underlying array. We found that a) Many of the arrays were just over the first resizing size, and b) There was a good heuristic that we could use to give them an initial size that would never have to be expanded and wouldn't result in huge amounts of waste.

This had a pretty dramatic effect on our GC times and the overall latency. I think this is where the JVM really shines - tons of tooling to help you profile and observe these kinds of details to help you figure out when you actually need to care about stuff like the initial array capacity.


Depends a lot on what you're doing too. I do a fair bit of heavy data processing work with my search engine (tokenizing something like a billion documents into arrays of words etc), and allocator contention has a pretty huge performance impact for that type of work.

My intuition is that the best thing is to aim for the expected median size, rather than the maximum as one might assume would be the most performant. The maximum strategy minimizes re-allocations, but at the expense of always making costlier allocations.


I think it depends a lot on the other details, especially how expensive the extra GC will be vs the wasted space. Hard to give a rule that will work in all contexts.

In our case, it wasn't a single hard-coded number - the input data gave us the upper bound, and the difference between the upper bound and the median case was so small that going with the upper bound worked out best.


I'm not the author, but I have contributed a few things to the project over the past year. The performance isn't anywhere close to the vanilla JVM - several times slower at best. It is entirely interpreted and there aren't any of the optimizations that have made their way into the JVM over the decades it has been around.

It has been a fun project to play around with for someone like me who thinks this kind of stuff is fun and interesting but will probably never get a chance to work on it full time. Cool to see it noticed, though!


Your last 2 sentences highlight the crux of it, I think - in the first sentence, you say "C developer" and in the second just "developers".

This actually does seem like a great icebreaker-type question for a C developer. I'm less convinced every developer should be able to go into that level of detail if they are doing Javascript or Python or whatever. Ideally they'd be able to at least reason through some of this and demonstrate some understanding of some of this, but I'm not sure it is a great icebreaker question for all developer roles.


Javascript doesn't even have ASCII - every string is UTF-16.


I think a lot depends on the context, the job, and the languages involved.

Of course there is a trivial solution in pretty much any language, for example something like str(Decimal(x) + 1) in python. That's dead-simple and anyone should be able to do at least that.

The later addendum that they want someone to know how data is store by the computer seems to imply that they want an answer that doesn't use these conversions, which gets a lot trickier depending on the context. I think you'd still expect someone who does C/C++ work to get there pretty quickly, but it is more than 15 seconds - you have to think about some corner cases and how you handle the string having to be resized in some situations.

But in some languages, it isn't obvious to me how you'd do it (especially since strings are immutable in many languages) and I think it is maybe a bit unfair to ask someone who does Java or Python or whatever to do it off the top of their head.


I agree that the goals and means to get to them are fuzzy and it feels frustrating at times, and things like affirmative action felt like trying to make two wrongs equal a right. But it also feels shitty and callous to say "Sorry about the whole segregation thing, hopefully everything evens out in a few hundred years or so.."

I think the hard part is that "Equality of Opportunity" is either so strictly defined that it is pointless, or it very quickly becomes really squishy and feels like "Equality of Outcome".

Most college applicants today are going to be something like 2 - 4 generations removed from official, legally sanctioned segregation (a situation I think most people would agree doesn't count as equality of opportunity). Would you argue that the average white student and average black student have equality of opportunity today?


Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: