I would say that with Julia it is easier to get a lousy performance. When it comes to “perfecting” performance, it comes down to improving algorithms and implementation details, and with the current tooling and dynamism that is easier with Julia.
A major advantage of Julia, as reported here in Discourse many times by people with a scientific background but who are not computer scientists nor the best programmers: after reading a technical article describing some advanced algorithm, a few hours were enough for them to implement concise Julia code whose syntax was identical to the mathematical notation used in the original article.
Julia also makes it easier to go lower level than is possible in Fortran for really perfecting performance.
Writing optimized BLAS is a lot easier than Julia than it would be in Fortran IMO.
Is JuliaSim a closed-source proprietary commercial product or an open source tool?
Still proprietary, like Simulink and for similar reasons. Though we should probably keep this thread on topic.
A few points regarding compatibility, reproducibility and encodings:
-
We take not making breaking changes in 1.x releases of Julia very seriously. We test every registered package in the entire open source ecosystem with every release to make sure we haven’t accidentally broken anything.
-
We keep binaries for every Julia release. As noted, they’re easy to install and use alongside each other. This is notably not the case for most C, C++ or Fortran compilers, which like to assume they own the entire system — if you want to use more than one version of gfortran at the same time, you’re going to need containers. The upshot is that if you need an old Julia version for whatever reason, you can easily install and use an old version just for one specific project.
-
While Julia 2.0 will by definition be somewhat breaking (or it would just be 1.x for some value of x), it seems like FUD to suppose that a release that hasn’t yet been made will change everything and break everyone’s code. Especially given that we’ve said the opposite many times: the way Julia code looks and feels is done. I’ll say it again: we are not interesting in making gratuitous annoying changes in Julia 2.0. I wrote more about the kinds of changes that are of interest here. In short, the vast majority of Julia 1 code will keep working in Julia 2.
-
The way Julia’s package manager works, when you have a Julia project, it gets its own project environment and the manifest file records the exact Julia version (as of Julia 1.7) and the exact version — down to the last bit — of every package dependency (since Julia 1.0) and every binary dependency (since Julia 1.3). You don’t need containers for perfect reproducibility. On the other hand, you cannot achieve this level or reproducibility in C or Fortran without containers — if you code depends on any libraries at all, you are at the mercy of whatever versions of those libraries happen to be installed on your system, and while Fortran the language is very careful about breaking changes, many libraries are not. As a result, you may not be able to compile your project at all, let alone get it to work as it once did. This is not a problem in Julia thanks to manifest files and immutable, content-addressed packages and binary artifacts.
-
Since Julia 1.5, packages and binaries are downloaded from package servers at pkg.julialang.org which are maintained by the Julia project and which are backed by a replicated system of storage servers that preserve copies of every package and artifact version that anyone ever installs through the package servers (both registered and unregistered versions of registered packages). That means that if you have a manifest that you instantiated via Julia’s package servers once, you will be able to install it forever. This is completely decoupled from GitHub and will continue to work even if GitHub disappears.
-
ASCII is certainly a venerable standard, but at this point Unicode is no less respectable and is certainly standardized. We’re not just making this stuff up. Julia source is UTF-8, which is a brilliantly designed and carefully specified superset of the ASCII encoding and rapidly becoming the encoding that is used everywhere for everything.
I suspect the mention of ASCII may have been a typo and ANSI was intended (see ANSI Standard Fortran), the focus being on community standardization.
The concentration of Julia influence at one company may concern some people with a long-term community focus. PostgreSQL for example has a rule that not too many of the core contributors can be at the same company.
Could you perhaps give a little bit more small examples on perhaps why Julia might be easier to get a lousy performance, and how to improve it? Thanks!
-
Use non-constant global variables. Solution: don’t use them. (In Fortran this is a non-issue because all variables have defined types, although not using them is a good practice anyway).
-
Allocate arrays inside loops. Solution: preallocate and reuse, or use static arrays. (In Fortran, even if a code needs to allocate, it is almost certain that stack allocations will be used and you get the “static arrays” behavior for free).
unless heap allocation is explicitly requested by a compiler flag.
I have read this many times but I don’t know what that means, not being a software developer. Without derailing the conversation, can you quickly point me to anywhere I can learn about that?
This is simple enough there may not be a single page focused on this. An example of the reused allocation pattern is that instead of doing this:
using Statistics
means = zeros(10_000)
for s in 1:10_000
x = rand(100)
means[s] = mean(x)
end
You should do this:
using Statistics, Random
means = zeros(10_000)
x = zeros(100)
for s in 1:10_000
rand!(x)
means[s] = mean(x)
end
Here you go from allocating x
inside the loop to pre-allocating it and reusing it.
can it be done “manually”, without using rand!
? (sorry, off topic)
Since Julia is aiming at writing concise/elegant/beautiful code without sacrificing performance.
I would wish that Julia be perhaps a little bit more intelligent/powerful in automatically optimizing situations like this
If you’re coming from Fortran to Julia for heavy number crunching, one performance aspect you might notice is just caused by Julia using the LLVM compiler, which doesn’t generate fused multiply-add (FMA) instructions by default. Thus, you need to opt-in explicitly. Luckily, Julia’s code introspection and manipulation tools make it relatively easy to do, using for example @fastmath
from Base or @muladd
from MuladdMacro. I have described that in a blog post on optimizing our hyperbolic PDE framework Trixi.jl.
Nevertheless, I definitely like using Julia (since v0.3 many years ago…) in my daily work as scientist working in numerical analysis and applied mathematics. We describe some of the nice aspects in our JuliaCon talk on Trixi.jl. Our team has a strong background in C, C++, and Fortran. Most of us have used an HPC Fortran code before. In our talk, Michael describes why we started to work on a new Julia code (Trixi.jl) and what we like about it. We still have a lot to do, in particular on the HPC side, but we’re pretty happy at the moment. Having said this, the Fortran code is of course still in use and will probably stay alive for quite some time.
I don’t think automatically changing rand(100)
into something like x = zeros(100)
combined with a later rand!(x)
will ever be done automatically. The reason is that while this transform may be “obvious” for people in this case, for the compiler it may not be and on top if that, the compiler has to be able to do this in the general case, which is going to be much more complicated than this little loop here.
I think even with the immutable array optimization PR, the API would be split into “give me readonly memory” and “give me writable memory”, in which case the compiler is free to transform the former into the rand!
version because from the semantics of the original code, there’s no danger in overwriting it.
I also think that such an automatic transform would make it much harder to reason about the performance of some piece of code, because it then relies on an optimization that may not always be applied, and coming up with simple rules for when it is applied is potentially very hard.
I agree that Julia takes compatibility and reproducibility very seriously, but I think that it is honest to say that Fortran also does it, and to a degree not seen before or after.
Without entering in a useless discussion, I want to clarify some things:
I agree. And Honestly, I will be more happy if Julia would never move to 2.X. This is basically what Fortran does.
¿What happens with your binaries if we move away from amd64? The statement of different compiler version is just wrong. I have several versions of gfortran installed (no containers). FreeBSD even allows you to get them from the package manager.
No intention to spread FUD. And good to know that these are the intentions. Sometimes I read long discusions like this (https://github.com/JuliaLang/julia/issues/35538) and I get really worried. These are the discussions that I do not really understand. If you do not like angle(z), or even if we all agree that is an unfortunate name, I would be very happy if it is just deprecated, but that it keeps working. I certainly would not understand making a sed -e "s/angle/arg/g"
for trivialities.
It is very good to know that Julia will live with the decisions made in the past (even if they are suboptimal), and only produce breaking changes if they bring improvements impossible to obtain by just adding things to 1.X.
Fortran code does not depend on many external libraries (maybe BLAS/LAPACK). The rest you code it yourself with only the standard… Most of the timees if you use some library you have to compile it yourself, which has the advantage that you have the complete sources of your code.
It would be great if there were a way to dowload and tar the exact sources of a project and that julia progresses in the direction of making possible to generate an executable from these sources (I know that there are works in thiss directions). If even to Julia 2.X, you could pass a command line argument (-v1) to geneate the executable of Julia 1.X that would be a very big step in my opinion.
I have taken a 30 years old fortran 77 code written for a CDC Cyber out of a magnetic tape. Passed one of its functions to a minimization code using genetic algorithms in fortran 2003 and everything compiled (and worked correctly) without a single line change in a Linux 64bit machine. I think that one has to acknowledge how amazing and good for scientific work this is.
I don’t think that’s 100% correct. Fortran 77 (fixed) syntax is incompatible with Fortran 90+ (free) syntax. While most compilers are able to digest both, you need to tell them which format to use, for example by using the right file extension or an appropriate compiler flag. While the end effect is that with a recent compiler you can likely compile both Fortran 77 and 90+, that doesn’t mean they’re completely compatible. That’s kind of like if Julia 2.x had also the possibility to run Julia 1.x code with a switch.
I think that this is not accurate. A compiler that supports the fortran 77/90/03/08 standards must allow you to produce a single executable with one file in fixed fortran that contains functions in fortran 77 and another file in free format that contains a fortran 90 module. (obviously you cannot mix fixed/free format in the same file, but these different formats can be part of the same code).
Note that this is very powerful… my routine for integration using Simpson rule was written many years ago. Today I can call this routine in a fortran 2008 program that uses paralellization with coarrays. I do not need to “port” my old codes.
To achieve this in Julia, it should be possible in Julia 2.X to write using MyModuleInV1
, and that it works without changing anything. If this is achieved, that would certainly be great, and basically equivalent to what fortran does (adding new functionalities, without breaking compatibility with previous standards). I would be extremely happy if something similar to this approach is taken: my current code would be perfectly portable to v2, without a single change.