What Rust construct uses nearbyint from libsystem_m? - performance

I've profiled my program with Valgrind and Callgrind and found that most of the time is spent in the nearbyint$fenv_access_off function.
I've found that it's a LLVM intrinsic, but which Rust language construct uses it? How can I avoid it?

Doing a search for nearbyint finds the related symbols nearbyintf32 and nearbyintf64. These are documented as returning the nearest integer to a floating point value. However, there appears to be no calls to that specific function.
fenv_access_off appears to be an OS X specific aspect of the math library.
The other thing in your trace is round. I can believe that round could use nearbyint. I also don't see any cases of round in the standard library that seem like they would occur in a tight loop.
Beyond this, anything is pure guessing.

I've reproduced it with:
fn main() {
let data:Vec<_> = (0..999999).map(|x|{
(x as f64).powf(2.2).round() as u8
}).collect();
}
so it seems as u8 is implemented using nearbyint.
It's the same speed as C uchar = round(pow(i, 2.2)), so I'll have to replace it with a good'ol lookup table…

Related

Does CLion possible evaluate a function when debugging Rust code?

A snip of Rust code:
pub fn main() {
let a = "hello";
let b = a.len();
let c =b;
println!("len:{}",c)
}
When debugging in CLion, Is it possible to evaluate a function? For example, debug the code step by step, now the code is running to the last line println!... and the current step stops here, by adding the expression a.len() to the watch a variable window, the IDE can't evaluate the a.len(). It says: error: no field named len
This is the same reason you can't make conditional breakpoints for Rust code:
Can't create a conditional breakpoint in VSCode-LLDB with Rust
I hope, I'm not too late to answer this, but with both lldb and gdb, Rust debugging capability is currently rather constrained.
Expressions that are straightforward work; anything complex is likely to produce issues.
My observations from rust-lldb trying this, are that only a small portion of Rust is understood by the expression parser.
There is no support for macros.
Non-used functions are not included in the final binary.
For instance, since that method is not included in the binary, you are unable to execute capacity() on the HashMap in the debugger.
Methods must be named as follows:
struct value.method(&struct value)
There is no technique that I've discovered to call monomorphized functions on generic structs (like HashMap).
For example, "hello" is a const char [5] including the trailing NUL byte. String constants "..." in lldb expressions are produced as C-style string constants.
Therefore, they are not valid functions

Halide::Expr' is not contextually convertible to 'bool' -- Storing values of functions in variables

I am new to using Halide and I am playing around with implementing algorithms first. I am trying to write a function which, depending on the value of the 8 pixels around it, either skips to the next pixel or does some processing and then moves on to the next pixel. When trying to write this I get the following compiler error:
84:5: error: value of type 'Halide::Expr' is not contextually convertible to 'bool'
if(input(x,y) > 0)
I have done all the tutorials and have seen that the select function is an option, but is there a way to either compare the values of a function or store them somewhere?
I also may be thinking about this problem wrong or might not be implementing it with the right "Halide mindset", so any suggestions would be great. Thank you in advance for everything!
The underlying issue here is that, although they are syntactically interleaved, and Halide code is constructed by running C++ code, Halide code is not C++ code and vice versa. Halide code is entirely defined by the Halide::* data structures you build up inside Funcs. if is a C control flow construct; you can use it to conditionally build different Halide programs, but you can't use it inside the logic of the Halide program (inside an Expr/Func). select is to Halide (an Expr which conditionally evaluates to one of two values) as if/else is to C (a statement which conditionally executes one of two sub-statements).
Rest assured, you're hardly alone in having this confusion early on. I want to write a tutorial specifically addressing how to think about staged programming inside Halide.
Until then, the short, "how do I do what I want" answer is as you suspected and as Khouri pointed out: use a select.
Since you've provided no code other than the one line, I'm assuming input is a Func and both x and y are Vars. If so, the result of input(x,y) is an Expr that you cannot evaluate with an if, as the error message indicates.
For the scenario that you describe, you might have something like this:
Var x, y;
Func input; input(x,y) = ...;
Func output; output(x,y) = select
// examine surrounding values
( input(x-1,y-1) > 0
&& input(x+0,y-1) > 0
&& ...
&& input(x+1,y+1) > 0
// true case
, ( input(x-1,y-1)
+ input(x+0,y-1)
+ ...
+ input(x+1,y+1)
) / 8
// false case
, input(x,y)
);
Working in Halide definitely requires a different mindset. You have to think in a more mathematical form. That is, a statement of a(x,y) = b(x,y) will be enforced for all cases of x and y.
Algorithm and scheduling should be separate, although the algorithm may need to be tweaked to allow for better scheduling.

What does :: mean in Rust?

What does the :: syntax in Rust, as seen here, mean:
fn chunk(n: uint, idx: uint) -> uint {
let sh = uint::BITS - (SHIFT * (idx + 1));
(n >> sh) & MASK
}
In languages like Haskell it means a type hint, but here the compiler already has an annotation of that values type, so it seems it's likely type casting.
Please review Appendix B: Operators and Symbols of The Rust Programming Language.
In this case, the double colon (::) is the path separator. Paths are comprised of crates, modules, and items.
The full path for your example item, updated for 1.0 is:
std::usize::BITS
Here, std is the crate, usize is a module, and BITS is the specific item — in this case a constant.
If you scroll up in your file, you'll see use core::usize. use adds the path to the set of items to look in. That's how you can get away with just saying usize::BITS. The core crate is an implementation detail of the façade that is the std crate, so you can just substitute std for core in normal code.
:: can also be used as a way to specify generic types when they cannot otherwise be inferred; this is called the turbofish.
See also:
What is the syntax: `instance.method::<SomeThing>()`?
Oops. I wasn't reading very clearly. In this case, it's just the normal way of referring to anything under a module. uint::BITS is a constant, it seems.

GCC and Clang: Turn off pure optimizations

I'm running a set of benchmarks comparing different libc string functions. The problem is that GCC and Clang are optimizing out the computations in the loops because the functions are marked "pure" and "const". Is there some way to either turn off that optimization or get around it?
I solved it! The solution was nasty, but it works:
volatile int x;
for (...)
{
// ...
x = (int)f(args);
}
I never use the value of x, so the cast won't be a problem. Better yet, now I don't get errors about not using return value of function declared with pure attribute.

try catch or type conversion performance in julia - (Julia 73 seconds, Python 0.5 seconds)

I have been playing with Julia because it seems syntactically similar to python (which I like) but claims to be faster. However, I tried making a similar script to something I have in python for tesing where numerical values are within a text file which uses this function:
function isFloat(s)
try:
float64(s)
return true
catch:
return false
end
end
For some reason, this takes a great deal of time for a text file with a reasonable amount of rows of text (~500000).
Why would this be? Is there a better way to do this? What general feature of the language can I understand from this to apply to other languages?
Here are the two exact scripts i ran with the times for reference:
python: ~0.5 seconds
def is_number(s):
try:
np.float64(s)
return True
except ValueError:
return False
start = time.time()
file_data = open('SMW100.asc').readlines()
file_data = map(lambda line: line.rstrip('\n').replace(',',' ').split(), file_data)
bools = [(all(map(is_number, x)), x) for x in file_data]
print time.time() - start
julia: ~73.5 seconds
start = time()
function isFloat(s)
try:
float64(s)
return true
catch:
return false
end
end
x = map(x-> split(replace(x, ",", " ")), open(readlines, "SMW100.asc"))
u = [(all(map(isFloat, i)), i) for i in x]
print(start - time())
Note also that you can use the float64_isvalid function in the standard library to (a) check whether a string is a valid floating-point value and (b) return the value.
Note also that the colons (:) after try and catch in your isFloat code are wrong in Julia (this is a Pythonism).
A much faster version of your code should be:
const isFloat2_out = [1.0]
isFloat2(s::String) = float64_isvalid(s, isFloat2_out)
function foo(L)
x = split(L, ",")
(all(isFloat2, x), x)
end
u = map(foo, open(readlines, "SMW100.asc"))
On my machine, for a sample file with 100,000 rows and 10 columns of data, 50% of which are valid numbers, your Python code takes 4.21 seconds and my Julia code takes 2.45 seconds.
This is an interesting performance problem that might be worth submitting to julia-users to get more focused feedback than SO will probably provide. At a first glance, I think you're hitting problems because (1) try/catch is just slightly slow to begin with and then (2) you're using try/catch in a context where there's a very considerable amount of type uncertainty because of lots of function calls that don't return stable types. As a result, the Julia interpreter spend its time trying to figure out the types of objects rather than doing your computation. It's a bit hard to tell exactly where the big bottlenecks are because you're doing a lot of things that are not very idiomatic in Julia. Also you seem to be doing your computations in the global scope, where Julia's compiler can't perform many meaningful optimizations due to additional type uncertainty.
Python is oddly ambiguous on the subject of whether using exceptions for control flow is good or bad. See Python using exceptions for control flow considered bad?. But even in Python, the consensus is that user code shouldn't use exceptions for control flow (although for some reason generators are allowed to do this). So basically, the simple answer is that you should not be doing that – exceptions are for exceptional situations, not for control flow. That is why almost zero effort has been put into making Julia's try/catch construct faster – you shouldn't be using it like that in the first place. Of course, we will probably get around to making it faster at some point.
That said, the onus is on us as the designers of Julia's standard library to make sure that we provide APIs that never force you to use exceptions for control flow. In this case, you need a function that allows you to try to parse something as a floating-point value and indicate whether that was possible or not – not by throwing an exception, but rather by returning normal values. We don't provide such an API, so this ultimately a shortcoming of Julia's standard library – as it exists right now. I've opened an issue to discuss this API design question: https://github.com/JuliaLang/julia/issues/5704. We'll see how it pans out.

Resources