Thank you for your interest in the 2017 Intel® Level Up Game Dev Contest. The contest closed on May 9, 2017.
Thank you for your interest in the 2017 Intel® Level Up Game Dev Contest. The contest closed on May 9, 2017.
The modern virtual reality market is new, but the idea of virtual worlds has existed in fiction for decades.
Austin Grossman is a sci-fi author who has written books such as the techno-thriller You: A Novel. He also helped write games like PC classics Deus Ex and System Shock as well as the more recent Dishonored series. At the GamesBeat Summit today in Berkley, California, Grossman discussed in an on-stage interview with Kim Pallister, VR expert at Intel, how sci-fi stories from our past can tell us about the future of virtual reality — and how we’re struggling how to deal with it.
Grossman brought up novels like Snow Crash and Ready Player One, which both featured VR social spaces. These ideas used to be science fiction, but modern virtual reality devices and online games are maker them closer to reality. But Grossman says that we’re like the dog who catches a car but doesn’t know what to do with it.
VR isn’t just an entertainment experience that people use for 10 minutes at a time, Grossman said, in novels. It is an integral part of society that people use for work as much as play. It’s also a tool used to escape from dystopian nightmares. In Ready Player One, many people are living in ghettos of skyscrapers made of trailer park homes. Its protagonist spends as much time in virtual reality as possible, using it to have access to things he doesn’t have in the real world: friends, education, and adventures.
This could present a danger to our VR future. What if people use the coming virtual worlds to escape the real one? Could we potentially forsake the planet and our ties to it in favor of a more palpable digital illusion?
So, the future of VR presented in fiction could be an unsettling one. But fiction hasn’t gotten everything right. In The Matrix, people need to be in pods or other constrictive devices to be connected to virtual worlds (and that’s besides the fact that most humans were imprisoned and having their energy sucked out by evil robots). But we aren’t using neural interfaces.
“It’s a wonderful thing that we got wrong,” Grossman said. Actual VR has players moving around. He says that this makes VR more exciting and less of a terrifying dystopia.
Grossman noted that world-building is the key skill needed for making enjoyable VR experiences. To make a world for a novel, that takes him two or three years of planning. But for modern virtual reality games, more work goes into designing and programming the experience. Less attention is given to narrative, characters, and history. These are the things that make people fall in love with and to live in a fictional world.
Licensing IP is kind of a cheat, Grossman says. It gives you an immediate world that audiences love. VR designers need to make new worlds of its own. The recent Star Trek: Bridge Crew is a good example of this. Beyond the gameplay, people enjoy the game just because it lets them be in Star Trek.
Virtual reality has the potential to change people and how they relate to each other. Forcing us to interact with others in unique ways. But Grossman noted that he also looks forward to having VR teach him. He anticipates full-body-tracking, since a VR program could then teach him how to dance. That certainly sounds more pleasant than having machine overlords plugging us into a placating VR world while they suck energy from our imprisoned bodies.
Clinical trials (CT) enable us to understand, diagnose, prevent, and treat diseases. Clinical research has led to making diabetes manageable, and prolonged the lives of AIDS and cancer patients. CT is a fundamental tool of modern medicine; it is the cornerstone of the drug development process.
Figure 1: Clinical trial process
The essence of conducting clinical trials is to evaluate the efficacy of new treatments and therapies. On average, it takes about 10 to 15 years to convey a medication from introductory revelation to the hands of patients, and can cost billions of dollars. Artificial intelligence (AI) can significantly reduce both the time and the cost by more than half. The rate of AI in these procedures permits organizations to create drugs with more precision, as compared to manual methodology. Experiments and analysis that would take human researchers weeks and months can be effectively conducted by AI within minutes.
For centuries, medical studies and clinical approaches have been a combination of religious beliefs, magical perspectives, medicinal herbs, and some science.
Back in 1796, smallpox was killing in the thousands, and tormenting others still alive with constant fear. Everyone from the rich to the poor was affected. While smallpox was killing people, Edward Jenner was busy making observations that milkmaids who had contracted cowpox, possibly from infected udders of cows, seemed to be immune to smallpox.
After collecting similar data points over several years, he performed a clinical trial. He scraped a pustule from a milkmaid, Sarah Nelmes, who had cowpox, and inserted the matter into a cut on the arm of his gardener’s son, a young boy called James Phipps. Six weeks later, he inoculated the boy with the smallpox virus. Jenner concluded that his hypothesis was correct when James Phipps did not get smallpox.
The word vaccination comes from vacca, Latin for cow. Jenner’s trials led to the discovery of vaccination. Jenner later conducted a mass vaccination, which prevented smallpox. This simple trial conquered epidemics from typhoid, to polio, to measles in later years. A clinical trial had saved thousands of lives!
Lightner Witmer developed practical work in clinical psychology at the University of Pennsylvania. Clinical psychology aims at preventing and relieving psychological distress and promoting personal development. It involves science and clinical knowledge to understand human patterns. Patients would have their skull shape (phrenology) and face (physiognomy) examined for the doctor to study their personality.
Such scientific data analysis methods and predictions based on information for an individual patient grew steadily in university laboratories by the late 1800s. Mental distress was then in the domain of psychiatrists,while psychologists nurtured the notion of non-curable disorders based on the size and shape of human anatomy as pure science. This changed when Lightner Witmer, then head of the psychology department at the University of Pennsylvania, leveraged the knowledge accumulated thus far to treat a young boy who had trouble with spelling. In 1896 he opened the first psychological clinic at Penn dedicated to helping children with disabilities, and coined the term clinical psychology, defined as the study of individuals, by observation or experimentation, with the intention of promoting change.
An effective use of insights hidden in data derived from patients had successfully differentiated treatable psychological issues from non-curable mental disorders. In fact, two clinical intelligence tests, Army Alpha (verbal skills) and Army Beta (nonverbal skills) were conducted on large groups of recruits during World War I, the success of which led to assessments becoming the core discipline of clinical psychology, eventually leading to treatments.
Clinical trials have continued to evolve since then, and have proven to be a miracle medical invention that has led to numerous lifesaving medicines we know today.
The complex drug pipeline process poses an enormous challenge: To move through expensive and time-consuming clinical trials efficiently and rapidly.
A core part of clinical evaluation involves the recruitment and selection of eligible patients who go through training programs for relevant clinical trials. To select and recruit eligible patients for clinical trials, clinicians manually analyze medical big data (MBD) and face multiple challenges consisting of the amount of medical data (volume), the number of types of medical data (variety), and the speed with which to process medical data (velocity) to determine inclusion of a patient into a clinical trial.
Figure 2: Clinical trial patient
Figure 3: Source: The Medical Futurist*
Though statistics have enabled us to design experiments precisely and to minimize errors in decision making, AI has the capacity to conduct such data analysis at the next level, enabling us to leverage not just a few hundred pieces of patient data, but millions. AI enables researchers to crunch enormous amounts of data within days or weeks, thereby reducing the heavy cost incurred in the pharmaceutical creation process. The result can also be customized to the individual, considering their own body's needs.
At an abstract level, artificial intelligence is considered a science that is concerned with the computational understanding of intelligent behavior, with the development of medical artifacts that exhibit such behavior. This behavior consists of the ability of the computer to simulate human-level cognitive performance such as visual perception, speech recognition, decision making, and language translation.
The rising cost of clinical trials and the difficulties involved in developing methodologies to acquire, analyze, and extract knowledge from medical big data in solving complex clinical problems accounts for the advancement in medical artificial intelligence (MAI).
Complementing people’s intelligence with machine intelligence, this augmented intelligence has an exponentially high impact. Machine learning can assist clinicians in their everyday clinical tasks, such as data manipulation and knowledge extraction, diagnosis formulation and the making of therapeutic decisions to predict clinical outcomes, and to improve the quality and lower the cost of clinical trials for better patient care.
Most clinical trials today are led without direct information from patients. Most information is being collected by third-party suppliers amid patient visits. With the invention of mobile, Internet of Things (IoT), and especially wearables, billions of individuals are now conveying important information effortlessly. This phenomenon offers a way to capture relevant information from patients in a continuous and convenient way. With the touch of a button, patients can choose to directly share their information for clinical trials over their mobile devices anywhere and everywhere. Additionally, the information captured is much more contextual, precise, and high quality; something we couldn’t even imagine with manual clinical trials.
Clinical trial processing systems are gradually moving to the cloud, with millions of mobile data points transmitting information, and custom frameworks analyzing the data. This lends a way to run continuous and self-learning trials with greater precision.
Patient data can now be shared among multiple clinics through the cloud infrastructure, making it more enticing for patients to participate in trials across the globe.
Given that the local recordings made over mobile devices are continuously transmitted to the cloud, it is now possible for clinics to catch anomalies in drug intake patterns among patients, in a real-time manner, and to even remind the patient if they forget to take their medication.
Not every human has the same body type; hence, different people can react differently to the same medication. Computerized reasoning is an effective method for anticipating drug results, since it treats a human gene with the entirety of all the collaborating qualities. With AI it is conceivable to predict which patients with a particular disease would benefit the most with a drug.
The application of artificial intelligence in clinical trials is enormous. Experts have created a web-based system that correctly selects and assigns cancer patients to clinical trials within 15 to 30 minutes and takes between 10 and 20 minutes to add new trials. The system is built to accommodate an increase in the number of patients selected for clinical trials, and suggests additional medical tests, while finding the most efficient test-ordering sequence that reduces the cost of recruitment.
Application of artificial intelligence in clinical trials and medical research continues to grow. In a Phase-III clinical trial funded by the National Institute of Neurological Disorders and Stroke, the antihypertensive treatment in acute cerebral hemorrhage (ATACH-II*), in collaboration with MentorMate*, designed a mobile phone app called the ATACH-II app. The app provides assistance with pre-screening, patient eligibility assessment, and randomization in a five-year multi-center, randomized, controlled, Phase-III trial to evaluate the efficacy of early, intensive antihypertensive treatment using intravenous nicardipine for acute hypertension in subjects with spontaneous supratentorial ICH.
In a Phase-II clinical trial conducted at 20 centers across the United States, the UK, Canada, and Germany, the Clot Lysis Evaluating Accelerated Resolution of Intraventricular Hemorrhage (CLEAR-IVH) trial investigators adopted the ATACH-II mobile phone app. The study recruited 52 patients diagnosed with intraventricular hemorrhage (IVH) with third or fourth ventricle obstruction. Each participant was given a thrombolytic, recombinant tissue plasminogen activator (tPA), via an extra ventricular catheter (EVD), in one of three dosing regimens over a three-day period.
Research shows that over 20 percent of all clinical trials fail because of non-adherence. AiCure* has developed a powerful, scalable, and real-time advanced non-adherence mobile technology platform that visually confirms medication ingestion. AiCure’s clinically validated platform combines the power of artificial intelligence with deep learning, computer vision, machine learning, and predictive analytics to make sure the right patient is taking the right medication at the right time. The real-time data will assist healthcare and pharmaceutical companies involved in conducting clinical trials to evaluate the efficacy of new treatments and therapies.
A skilled radiologist can use systems like AI tools to run tests, and focus on subjective, common sense, human decision making.
Figure 4: IBM Watson* Analytics
After a patient’s tumor is sequenced by Quest Diagnostics*,Watson* analyzes the genetic alterations found to help identify potentially treatable mutations. This analysis can help oncologists identify targeted therapies for each patient’s individual cancer.
AI is still in the infant stage of development and will not be able to replace a doctor.
Due to AI’s ability to understand natural language such as clinical notes, along with structured data such as dates and numbers, and the ability to generate hypotheses based on evidence, it is being considered as the fourth industrial revolution, for which the healthcare and pharmaceutical industries are seen as the biggest beneficiaries.
Artificial intelligence holds even greater promise, not only in transforming clinical research, but also in reducing the cost associated with disease management, successful ageing, and the discovery and development of new medical innovations. For example, it cost USD 200 billion and €125 billion to manage non-communicable diseases in America and Europe, respectively, per year, while in the United States alone it costs three to five times more to provide support for successful ageing for someone aged 65 and over than for someone younger, a cost which is expected to decrease significantly with AI!
https://www.cs.cmu.edu/~eugene/research/full/trial-knowledge.pdf
https://www.sciencedaily.com/releases/2016/04/160427095057.htm
https://www.nhlbi.nih.gov/studies/clinicaltrials
http://www.cbsnews.com/news/artificial-intelligence-making-a-difference-in-cancer-care/
http://www.thenakedscientists.com/articles/interviews/story-smallpox
Welcome and Agenda Talk at UC Berkeley Student Workshop for AI
Bob Duffy welcomes students and reviews the program agenda for the student AI workshop.
Intel® Student Developer AI Workshop—University of California Berkeley
Sneak peek into the Artificial Intelligence workshops hosted by Intel at Universities across the globe.
The Human Side of AI: Affective Computing
Affective Computing can make us aware of our emotional state, helping us take better decisions, help us to help others, or help machines make decisions to enrich our lives. There is another exciting use for emotional data: Machine Learning.
From Smart to Intelligent Vehicles Through Affective Computing
Affective Computing is a capability by which devices understand human emotions and use that understanding to take actions. In this video we look at an example of what can be done with emotional data while you are driving.
Affective Computing in the Home
Affective Computing is a capability by which devices understand human emotions and take actions based on that understanding. In this we look at what can be done with emotional data inside your home.
Affective Computing in the Classroom
Affective Computing helps devices understand human emotions and take actions that can benefit the user. This technology can even be used in a classroom setting. In this video we look at an example based on the work by members of Intel Labs.
Can Technology Replace The Eye?
Data is Much More Than Numbers. Data is the tool we use to communicate a story effectively. Data is the tool that enables us to make informed decisions.
Clinical Trial Patient Screening via Genome Analysis
Genome sequencing and analysis increases patient screening accuracy.
How to Get Started Developing for Automated Driving
From safe roads to enjoyable commutes, automated driving is poised to change lives and society for the better.
Predicting Patient Costs
Session from the second Machine Learning Meetup in Portland, Oregon.
How to Get Started as a Developer in AI
The promise of artificial intelligence has captured our cultural imagination since at least the 1950s—inspiring computer scientists to create new and increasingly complex technologies.
Scaling to Meet the Growing Needs of AI
Scaling distributed machine learning is challenging as it pushes the limits of available data and model parallelism.
An Artificial Intelligence Primer for Developers
Intel is not merely invested in the growth of AI, we are committed to fueling the AI revolution, making it one of our top priorities.
Intel’s New Processors: A Machine-learning Perspective
This talk discusses the usage of Intel’s new server processors for various machine-learning tasks.
The Shallow End of Deep Learning
Watch Ted Willke’s presentation about deep learning
from the first Intel Machine Learning meetup.
What is Saffron* Technology?
This technology enables customers to make better decisions through its natural intelligence platform.
ML-Bench 1.0 Constructing and Analyzing a Machine-Learning Benchmark
This talk describes the analysis method used for building this machine-learning benchmark.
Security and Machine Learning in an Open Source Community
John Whiteman discusses security and machine learning.
Pushing Machine Learning to a New Level
Pushing Machine Learning to a New Level with Intel® Xeon® processors and Intel® Xeon Phi™ processors.
Superior Performance Commits Kyoto University to CPUs Over GPUs
The Kyoto University team recognized that the performance of the open source Theano* C++ multi-core code could be significantly improved.
Tencent* Uses Machine Learning for In-Game Purchase Recommendation System on Intel Xeon Processors
Tencent* uses an in-game purchase recommendation system employing the machine learning method to enhance the online gaming user experience.
Introducing the new Packed APIs for GEMM
Introducing Packed APIs for GEMM Matrix-matrix multiplication (GEMM) is a fundamental operation in many scientific, engineering, and learning applications.
What is All the Buzz About Machine Learning
Machine learning is changing the balance of labor between the decision-making role of humans, and the number-crunching roles of computers. Pradeep Dubey discusses the excitement behind the theories and practices that machine learning is redefining.
Machine Learning Introduction: Regression and Classification
This video examines two of the main problems with machine learning, regression, and classification.
Intel® Xeon Phi™ processors Delivers Competitive Performance for Deep Learning—And Getting Better Fast
Baidu’s recently announced deep learning benchmark, DeepBench, documents performance for the lowest-level compute and communication primitives for deep learning applications.
Using a Deep Learning Approach to Model Behavior in MOOCs
Berkeley graduate student Steven Tang shows his approach to modeling behavior in Massive Open Online Courses.
From Smart to Intelligent Vehicles Through Affective Computing
Affective Computing is a capability by which devices understand human emotions and use that understanding to take actions. In this video we look at an example of what can be done with emotional data while you are driving.
Deep Learning for Virtual Cancer Screening
Demo: Deep learning for virtual screening.
Accelerating Neural Networks with Binary Arithmetic
The original article is published on Intel® Nervana™ AI solution site: Accelerating Neural Networks with Binary Arithmetic. Please go to Nervana Homepage (nervanasys.com) to learn more on Intel Nervana’s deep learning technologies.
Intel® Xeon Phi™ Delivers Competitive Performance for Deep Learning—And Getting Better Fast
Baidu’s recently announced deep learning benchmark, DeepBench, documents performance for the lowest-level compute and communication primitives for deep learning (DL) applications.
Superior Performance Commits Kyoto University to CPUs Over GPUs
The Kyoto University team recognized that the performance of the open source Theano* C++ multi-core code could be significantly improved.
Distributed Training of Deep Networks on Amazon Web Services* (AWS)
In this article, we provide the steps to set up the AWS CloudFormation* environment to train deep networks using the Caffe* network.
A Brief Overview of Deep Learning Using Intel® Architectures
Deep learning attempts to model various levels of abstraction within data. There are various tools to train and deploy deep networks, and Intel is actively working with the deep learning community to optimize many of the frameworks to significantly improve computational performance on Intel® architectures.
Introduction to Deep Learning with Intel® Nervana™ AI solution and the neon™ framework
Learn about Intel® Nervana™ AI solution deep learning technology including the neon™ framework.
Deep Learning Demos of the Intel® Nervana™ AI solution Platform Using neon™ framework
Walkthrough of Neon demos using Jupyter* notebooks such as MNIST and sentiment analysis with LSTM.
Hands-on Deep Learning Workshop: Intel® Nervana™ AI solution Artificial Intelligence—Part 1
In this talk, we will give an overview of the Intel® Nervana™ DL platform and get some hands-on experience using this platform to train and execute deep learning models.
Hands-on Deep Learning Workshop: Intel® Nervana™ AI solution Artificial Intelligence—Part 2
In this talk, we will give an overview of the Intel® Nervana™ AI solution DL platform and get some hands-on experience using this platform to train and execute deep learning models.
Intel® Nervana™ AI solution’s End-to-End Speech Recognition with neon™
This Meetup covers the basic ideas that go into building an end-to-end speech recognition system trained entirely using deep learning techniques. You will have understanding of the high level concepts that go into training a speech recognition engine in an end-to-end fashion.
Intel® Nervana™ AI solution Engine Delivers Deep Learning at Ludicrous Speed!
Intel® Nervana™ AI solution is currently developing the Intel® Nervana™ Solution Engine, an application specific integrated circuit (ASIC) that is custom designed and optimized for deep learning.
Distributed, Docker*-ized Deep Learning with Intel® Nervana™ technology, neon™ framework, and Pachyderm*
The recent advances in machine learning and artificial intelligence are amazing! It seems like we see something groundbreaking every day, from self-driving cars, to AIs learning complex games.
How to Install the neon™ framework on Ubuntu*
This article presents a simple step-by-step way to install the neon™ framework in Ubuntu* 14.04 using the Anaconda* Python* distribution.
Transfer Learning Using neon™
Please check the original article at Nervana’s site to learn more about this topic and more on Intel Nervana’s deep learning frameworks.
Webinar: Deep Learning 101
This webinar describes various deep learning usages and highlights those in which Caffe* is used.
Caffe* Optimized for Intel® Architecture: Applying Modern Code Techniques
This paper demonstrates a special version of Caffe*—a deep learning framework originally developed by the Berkeley Vision and Learning Center (BVLC)—that is optimized for Intel® architecture.
Distributed Training of Deep Networks on Amazon Web Services* (AWS)
In this article, we provide the steps to set up the AWS CloudFormation* environment to train deep networks using the Caffe* network.
How to Install Caffe* Optimized for Intel® Architecture
This video shows you how to install Caffe* Optimized for Intel® architecture.
What is Intel® Optimized Caffe*
Caffe* is a deep learning framework that is useful for convolutional and fully connected networks, and recently recurrent neural networks were added. There are various forks of Caffe branches that cover a variety of tasks.
Recipe: Optimized Caffe* for Deep Learning on Intel® Xeon Phi™ processor x200
The computer learning code Caffe* has been optimized for Intel® Xeon Phi™ processors. This article provides detailed instructions on how to compile and run this Caffe* optimized for Intel® architecture to obtain the best performance on Intel Xeon Phi processors.
Training and Deploying Deep Learning Networks with Caffe* Optimized for Intel® Architectures
Caffe* is a deep learning framework developed by the Berkeley Vision and Learning Center (BVLC). Caffe optimized for Intel architecture is currently integrated with the latest release of Intel® Math Kernel Library (Intel® MKL).
Caffe* Training on Multi-node Distributed-memory Systems Based on Intel Xeon Processor E5 Family
Caffe is a deep learning framework developed by the Berkeley Vision and Learning Center (BVLC) and one of the most popular community frameworks for image recognition.
Single Node Caffe Scoring and Training on Intel® Xeon E5-Series Processors
Deep Neural Network (DNN) applications grow in importance in various areas including internet search engines and medical imaging.
Intel and Facebook* Collaborate to Boost Caffe2 Performance on Intel CPU’s
Every day, the world generates more and more information—text, pictures, videos and more. In recent years, artificial intelligence and deep learning have improved several applications that help people better understand this information.
BigDL: Distributed Deep Learning on Apache Spark*
As the leading framework for Distributed ML, the addition of deep learning to the super-popular Spark framework becomes increasingly important.
Intel’s Optimized Tools and Frameworks for Machine Learning and Deep Learning
This article gives an introduction to Intel’s optimized machine learning and deep learning tools and frameworks.
Getting Started with Intel® Software Optimization for Theano* and Intel® Distribution for Python*
Theano* is a Python* library developed at the LISA lab to define, optimize, and evaluate mathematical expressions, including the ones with multi-dimensional arrays (numpy.ndarray).
Distributed Machine Learning on Apache Spark*
Radhika Rangarajan, Engineering Program Manager at Intel, discusses distributed machine learning on Apache Spark*.
TensorFlow* Optimizations on Modern Intel® Architectures
This paper introduces the Artificial Intelligence (AI) community to TensorFlow* optimizations on Intel® Xeon® processors and Intel® Xeon Phi™ processor-based systems.
Introduction to BigDL on Apache Spark* Part1
Addressing the need for a unified platform for big data analytics and deep learning, Intel recently released BigDL, an open source distributed deep learning library for Apache Spark*.
BigDL: Bring Deep Learning to the Fingertips of Big Data Users and Data Scientists
This blog provides an overview of recent enhancements available in the BigDL 0.1.0 release (as well as in the upcoming 0.1.1 release).
Deploying BigDL on Microsoft’s Azure* Data Science Virtual Machine
To make it easier to deploy BigDL, we created a “Deploy to Azure” button on top of the Linux* (Ubuntu*) edition of the Data Science Virtual Machine (DSVM).
BigDL—Scale-out Deep Learning on Apache Spark* Cluster
Learn how to install and use BigDL for training and testing some of the commonly used deep neural network models on Apache Spark.
Intel’s Optimized Tools and Frameworks for Machine Learning and Deep Learning
This article gives an introduction to Intel’s optimized machine learning and deep learning tools and frameworks.
Improving the Performance of Principal Component Analysis with Intel® Data Analytics Acceleration Library (Intel® DAAL)
This article discusses an unsupervised machine-learning algorithm called principal component analysis (PCA) that can be used to simplify the data.
Accelerating Deep Learning and Machine Learning with Intel Libraries
Accelerating Deep Learning and Machine Learning with Intel Libraries.
Introducing DNN primitives in Intel® Math Kernel Library (Intel® MKL)
Deep Neural Networks (DNNs) are on the cutting edge of the Machine Learning domain. These algorithms received wide industry adoption in the late 1990s and were initially applied to tasks such as handwriting recognition on bank checks.
Improving Support Vector Machine with Intel® Data Analytics Acceleration Library
Improving the Performance of Support Vector Machine with Intel® Data Analytics Acceleration Library Introduction.
Using Intel® Data Analytics Acceleration Library (Intel® DAAL) on Matlab*
Intel® Data Analytics Acceleration Library is a high performance library, which provides a rich set of algorithms, ranging from the ranging from the most basic descriptive statistics for datasets to more advanced data mining and machine learning algorithms.
Using Intel® Data Analytics Acceleration Library to Improve the Performance of Naïve Bayes Algorithm in Python*
This article discusses machine learning and describes a machine learning method/algorithm called Naïve Bayes.
Intel® DAAL
Kent Moffat, Senior Product Manager at Intel, discusses Intel® Data Analytics Acceleration Library (Intel® DAAL) and Intel® Math Kernel Library (Intel® MKL) and how to get started.
Faster Machine Learning and Data Analytics Using Intel® Performance Libraries
Develop software that transforms data to decision-making sooner with Intel Data Analytics Acceleration Library (Intel DAAL) and Intel Math Kernel Library (Intel MKL) 2017.
Remove Python* Performance Barriers for Machine Learning
This webinar highlights significant performance speed-ups achieved by implementing multiple Intel tools and techniques for high-performance Python*.
Getting Started with Intel Software Optimization for Theano* and Intel® Distribution for Python*
Theano* is a Python* library developed at the LISA lab to define, optimize, and evaluate mathematical expressions, including the ones with multi-dimensional arrays (numpy.ndarray).
How to Install the Python* Version of Intel® Data Analytics Acceleration Library (Intel® DAAL)
Intel Data Analytics Acceleration Library (Intel DAAL) is a software solution that offers building blocks covering all the stages of data analytics, from preprocessing to decision making.
Using Intel® Data Analytics Acceleration Library to Improve the Performance of Naïve Bayes Algorithm in Python*
This article discusses machine learning and describes a machine learning method/algorithm called Naïve Bayes.
Intel Distribution for Python*
Intel Distribution for Python* gives ready access to tools and techniques for high performance to supercharge all your Python applications on modern Intel® platforms.
Perhaps, readers remember my article titled "Last line effect". It describes a pattern I've once noticed: in most cases programmers make an error in the last line of similar text blocks. Now I want to tell you about a new interesting observation. It turns out that programmers tend to make mistakes in functions comparing two objects. This statement looks implausible; however, I'll show you a great number of examples of errors that may be shocking to a reader. So, here is a new research, it will be quite amusing and scary.
Here is my statement: programmers quite often make mistakes in rather simple functions that are meant to compare two objects. This claim is based on the experience of our team in checking a large number of open source projects in C, C++ and C#.
The functions we are going to consider here are IsEqual, Equals, Compare, AreEqual and so on or overloaded operators as ==, !=.
I noticed that when writing articles, very often I come across errors related to the comparison functions. I decided to explore this question in detail and examined the base of errors we found. I did a search of functions throughout the base containing words Cmp, Equal, Compare and such. The result was very impressive and shocking.
In fact this story is similar to the one we had when writing the article "Last line effect". Similarly, I noticed an anomaly and decided to explore it more carefully. Unfortunately, unlike the aforementioned article, I don't know how to bring statistics here and which figures to provide. Perhaps, later I'll come up with a solution with the statistics. At this point I am guided by intuition and can only share my feelings. They see that there are a lot of errors in the comparison functions and I am sure, you will get the same feeling when you see that huge amount of truly impressive examples.
For a moment let's go back to the article "Last line effect". By the way, if you haven't read it, I suggest taking a break and looking at it. There is a more detailed analysis of this topic: "The last line effect explained"
In general, we can conclude that the cause of the errors in the last lined is related to the fact that the developer has already mentally moved to the new lines/tasks instead of focusing on the completion of the current fragment. As a result - when writing similar blocks of text, there is a higher probability that a programmer will make an error in the last one.
I believe that in the case of writing a comparison function, a developer in general often don't focus on it, considering it to be too trivial. In other words, he writes the code automatically, without thinking over it. Otherwise, it is not clear how one can make an error like this:
bool IsLuidsEqual(LUID luid1, LUID luid2) { return (luid1.LowPart == luid2.LowPart) && (luid2.HighPart == luid2.HighPart); }
PVS-Studio analyzer detected this error in the code of RunAsAdmin Explorer Shim (C++) project: V501 There are identical sub-expressions to the left and to the right of the '==' operator: luid2.HighPart == luid2.HighPart RAACommon raacommonfuncs.cpp 1511
A typo. In the second line it should be: luid1.HighPart == luid2.HighPart.
The code is very simple. Apparently, the simplicity of code spoils everything. A programmer immediately thinks of the task to write such a function as standard and uninteresting. He instantly thinks of the way to write the function and he has just to implement the code. This is a routine, but unfortunately an inevitable process to start writing more important, complex and interesting code. He is already thinking about the new task... and as a result - makes an error.
In addition, programmers rarely write unit tests for such functions. Again the simplicity of these functions prevents from it. It seems that it would be too much to test them, as these functions are simple and repetitive. A person has written hundreds of such functions in his life, can he make an error in another function? Yes, he can and he does.
I would also like to note that we aren't talking about code of students who are just learning to program. We are talking about bugs in the code of such projects as GCC, Qt, GDB, LibreOffice, Unreal Engine, CryEngine 4 V Chromium, MongoDB, Oracle VM Virtual Box, FreeBSD, WinMerge, the CoreCLR, MySQL, Mono, CoreFX, Roslyn, MSBuild, etc. It's all very serious.
We are going to have a look at so many diverse examples that it would be scary to sleep at night.
All errors in comparison functions will be divided into several patterns. In the article we'll be talking about errors in projects in C, C++ and C#, but it makes no sense to separate these languages, as most of the patterns are similar for different languages.
Very often in the comparison functions there is a need to make such checks:
Sometimes programmers think that is more elegant to use the same operator <, but to switch the variables.
However, due to the inattentiveness, we get such checks:
In fact, one and the same comparison is done twice here. Perhaps, it's not clear what it is about here, but we'll get to the practical examples and it'll all become clearer.
string _server; .... bool operator<( const ServerAndQuery& other ) const { if ( ! _orderObject.isEmpty() ) return _orderObject.woCompare( other._orderObject ) < 0; if ( _server < other._server ) return true; if ( other._server > _server ) return false; return _extra.woCompare( other._extra ) < 0; }
PVS-Studio analyzer detected this error in the code of MongoDB (C++): V581 The conditional expressions of the 'if' operators situated alongside each other are identical. Check lines: 44, 46. parallel.h 46
This condition:
if ( other._server > _server )
Will always be false, as the same check was done two lines before. Correct code variant:
if ( _server < other._server ) return true; if ( other._server < _server ) return false;
This error was detected in the code of Chromium project (C++):
enum ContentSettingsType; struct EntryMapKey { ContentSettingsType content_type; ... }; bool OriginIdentifierValueMap::EntryMapKey::operator<( const OriginIdentifierValueMap::EntryMapKey& other) const { if (content_type < other.content_type) return true; else if (other.content_type > content_type) return false; return (resource_identifier < other.resource_identifier); }
PVS-Studio warning: V517 The use of 'if (A) {...} else if (A) {...}' pattern was detected. There is a probability of logical error presence. Check lines: 61, 63. browser content_settings_origin_identifier_value_map.cc 61
That was a C++ example, now it's C# turn. The next error was found in the code of IronPython and IronRuby (C#).
public static int Compare(SourceLocation left, SourceLocation right) { if (left < right) return -1; if (right > left) return 1; return 0; }
PVS-Studio warning (C#): V3021 There are two 'if' statements with identical conditional expressions. The first 'if' statement contains method return. This means that the second 'if' statement is senseless. SourceLocation.cs 156
I think there is no need in explanation.
Note. For C# there was just one example of an error, but for C++ - two. In general, there will be less bugs in the C# code, than for C/C++. But I do not recommend rushing to the conclusion that C# is much safer. The thing is that PVS-Studio analyzer has only recently learned to check C# code relatively recently, and we have just checked less projects written in C#, than in C and C++.
The comparison functions usually consist of successive comparisons of structure/class members. This code tends to be more erronreous, when the member of the class starts being compared with itself. I can specify two subtypes of errors.
In the first case, a programmer forgets to specify the name of the object and writes in the following way:
return m_x == foo.m_x && m_y == m_y && // <= m_z == foo.m_z; In the second case, the same name of the object is written. return zzz.m_x == foo.m_x && zzz.m_y == zzz.m_y && // <= zzz.m_z == foo.m_z;
Let's take a closer look at practical examples of this pattern. Pay attention that incorrect comparison often occurs in the last block of similar code blocks, which reminds us of the "last line effect" again.
The error is found in the code of Unreal Engine 4 (C++) project:
bool Compare(const FPooledRenderTargetDesc& rhs, bool bExact) const { .... return Extent == rhs.Extent&& Depth == rhs.Depth&& bIsArray == rhs.bIsArray&& ArraySize == rhs.ArraySize&& NumMips == rhs.NumMips&& NumSamples == rhs.NumSamples&& Format == rhs.Format&& LhsFlags == RhsFlags&& TargetableFlags == rhs.TargetableFlags&& bForceSeparateTargetAndShaderResource == rhs.bForceSeparateTargetAndShaderResource&& ClearValue == rhs.ClearValue&& AutoWritable == AutoWritable; // <= }
PVS-Studio warning: V501 There are identical sub-expressions to the left and to the right of the '==' operator: AutoWritable == AutoWritable rendererinterface.h 180
The code of Samba (C) project:
static int compare_procids(const void *p1, const void *p2) { const struct server_id *i1 = (struct server_id *)p1; const struct server_id *i2 = (struct server_id *)p2; if (i1->pid < i2->pid) return -1; if (i2->pid > i2->pid) return 1; return 0; }
PVS-Studio warning: V501 There are identical sub-expressions to the left and to the right of the '>' operator: i2->pid > i2->pid brlock.c 1901
The code of MongoDB (C++) project:
bool operator==(const MemberCfg& r) const { .... return _id==r._id && votes == r.votes && h == r.h && priority == r.priority && arbiterOnly == r.arbiterOnly && slaveDelay == r.slaveDelay && hidden == r.hidden && buildIndexes == buildIndexes; // <= }
PVS-Studio warning: V501 There are identical sub-expressions to the left and to the right of the '==' operator: buildIndexes == buildIndexes rs_config.h 101
The code of Geant4 Software (C++) project:
inline G4bool G4FermiIntegerPartition:: operator==(const G4FermiIntegerPartition& right) { return (total == right.total && enableNull == enableNull && // <= partition == right.partition); }
PVS-Studio warning: V501 There are identical sub-expressions to the left and to the right of the '==' operator: enableNull == enableNull G4hadronic_deex_fermi_breakup g4fermiintegerpartition.icc 58
The code of LibreOffice (C++) project:
class SvgGradientEntry { .... bool operator==(const SvgGradientEntry& rCompare) const { return (getOffset() == rCompare.getOffset()&& getColor() == getColor() // <=&& getOpacity() == getOpacity()); // <= } .... }
PVS-Studio warning: V501 There are identical sub-expressions to the left and to the right of the '==' operator: getColor() == getColor() svggradientprimitive2d.hxx 61
The code of Chromium (C++) project:
bool FileIOTest::MatchesResult(const TestStep& a, const TestStep& b) { .... return (a.data_size == a.data_size && // <= std::equal(a.data, a.data + a.data_size, b.data)); }
PVS-Studio warning: V501 There are identical sub-expressions to the left and to the right of the '==' operator: a.data_size == a.data_size cdm_file_io_test.cc 367
The code of FreeCAD (C++) project:
bool FaceTypedBSpline::isEqual(const TopoDS_Face &faceOne, const TopoDS_Face &faceTwo) const { .... if (surfaceOne->IsURational() != surfaceTwo->IsURational()) return false; if (surfaceTwo->IsVRational() != // <= surfaceTwo->IsVRational()) // <= return false; if (surfaceOne->IsUPeriodic() != surfaceTwo->IsUPeriodic()) return false; if (surfaceOne->IsVPeriodic() != surfaceTwo->IsVPeriodic()) return false; if (surfaceOne->IsUClosed() != surfaceTwo->IsUClosed()) return false; if (surfaceOne->IsVClosed() != surfaceTwo->IsVClosed()) return false; if (surfaceOne->UDegree() != surfaceTwo->UDegree()) return false; if (surfaceOne->VDegree() != surfaceTwo->VDegree()) return false; .... }
PVS-Studio warning: V501 There are identical sub-expressions 'surfaceTwo->IsVRational()' to the left and to the right of the '!=' operator. modelrefine.cpp 780
The code of Serious Engine (C++) project:
class CTexParams { public: inline BOOL IsEqual( CTexParams tp) { return tp_iFilter == tp.tp_iFilter && tp_iAnisotropy == tp_iAnisotropy && // <= tp_eWrapU == tp.tp_eWrapU && tp_eWrapV == tp.tp_eWrapV; }; .... };
PVS-Studio warning: V501 There are identical sub-expressions to the left and to the right of the '==' operator: tp_iAnisotropy == tp_iAnisotropy gfx_wrapper.h 180
The code of Qt (C++) project:
inline bool qCompare(QImage const &t1, QImage const &t2, ....) { .... if (t1.width() != t2.width() || t2.height() != t2.height()) { .... }
PVS-Studio warning: V501 There are identical sub-expressions to the left and to the right of the '!=' operator: t2.height() != t2.height() qtest_gui.h 101
The code of FreeBSD (C) project:
static int compare_sh(const void *_a, const void *_b) { const struct ipfw_sopt_handler *a, *b; a = (const struct ipfw_sopt_handler *)_a; b = (const struct ipfw_sopt_handler *)_b; .... if ((uintptr_t)a->handler < (uintptr_t)b->handler) return (-1); else if ((uintptr_t)b->handler > (uintptr_t)b->handler) // <= return (1); return (0); }
PVS-Studio warning: V501 There are identical sub-expressions '(uintptr_t) b->handler' to the left and to the right of the '>' operator. ip_fw_sockopt.c 2893
The code of Mono (C#) project:
static bool AreEqual (VisualStyleElement value1, VisualStyleElement value2) { return value1.ClassName == value1.ClassName && // <= value1.Part == value2.Part && value1.State == value2.State; }
PVS-Studio warning: V3001 There are identical sub-expressions 'value1.ClassName' to the left and to the right of the '==' operator. ThemeVisualStyles.cs 2141
The code of Mono (C#) project:
public int ExactInference (TypeSpec u, TypeSpec v) { .... var ac_u = (ArrayContainer) u; var ac_v = (ArrayContainer) v; .... var ga_u = u.TypeArguments; var ga_v = v.TypeArguments; .... if (u.TypeArguments.Length != u.TypeArguments.Length) // <= return 0; .... }
PVS-Studio warning: V3001 There are identical sub-expressions 'u.TypeArguments.Length' to the left and to the right of the '!=' operator. generic.cs 3135
The code of MonoDevelop (C#) project:
Accessibility DeclaredAccessibility { get; } bool IsStatic { get; } private bool MembersMatch(ISymbol member1, ISymbol member2) { if (member1.Kind != member2.Kind) { return false; } if (member1.DeclaredAccessibility != // <=1 member1.DeclaredAccessibility // <=1 || member1.IsStatic != member1.IsStatic) // <=2 { return false; } if (member1.ExplicitInterfaceImplementations().Any() || member2.ExplicitInterfaceImplementations().Any()) { return false; } return SignatureComparer .HaveSameSignatureAndConstraintsAndReturnTypeAndAccessors( member1, member2, this.IsCaseSensitive); }
PVS-Studio warning: V3001 There are identical sub-expressions 'member1.IsStatic' to the left and to the right of the '!=' operator. CSharpBinding AbstractImplementInterfaceService.CodeAction.cs 545
The code of Haiku (C++) project:
int __CORTEX_NAMESPACE__ compareTypeAndID(....) { int retValue = 0; .... if (lJack && rJack) { if (lJack->m_jackType < lJack->m_jackType) // <= { return -1; } if (lJack->m_jackType == lJack->m_jackType) // <= { if (lJack->m_index < rJack->m_index) { return -1; } else { return 1; } } else if (lJack->m_jackType > rJack->m_jackType) { retValue = 1; } } return retValue; }
PVS-Studio warning: V501 There are identical sub-expressions to the left and to the right of the '<' operator: lJack->m_jackType < lJack->m_jackType MediaJack.cpp 783
Just below there is exactly the same error. As I understand, in both cases a programmer forgot to replace lJack with rJack.
The code of CryEngine V (C++) project:
bool CompareRotation(const Quat& q1, const Quat& q2, float epsilon) { return (fabs_tpl(q1.v.x - q2.v.x) <= epsilon)&& (fabs_tpl(q1.v.y - q2.v.y) <= epsilon)&& (fabs_tpl(q2.v.z - q2.v.z) <= epsilon) // <=&& (fabs_tpl(q1.w - q2.w) <= epsilon); }
PVS-Studio warning: V501 There are identical sub-expressions to the left and to the right of the '-' operator: q2.v.z - q2.v.z entitynode.cpp 93
This type of error occurs in programs written in C and C++ and is caused by incorrect use of the sizeof operator. The error in evaluating not the size of the object, but the size of the pointer. Example:
T *a = foo1(); T *b = foo2(); x = memcmp(a, b, sizeof(a));
Instead of the size of the T structure, a size of the pointer gets evaluated. The size of the pointer depends on the used data model, but usually it is 4 or 8. As a result, more or less bites in the memory get compared than take the structure.
Correct variant of the code:
x = memcmp(a, b, sizeof(T));
or
x = memcmp(a, b, sizeof(*a));
Now let's move on to the practical part. Here is how such a bug looks in the code of CryEngine V (C++) code:
bool operator==(const SComputePipelineStateDescription& other) const { return 0 == memcmp(this, &other, sizeof(this)); }
PVS-Studio warning: V579 The memcmp function receives the pointer and its size as arguments. It is possibly a mistake. Inspect the third argument. graphicspipelinestateset.h 58
The code of Unreal Engine 4 project (C++):
bool FRecastQueryFilter::IsEqual( const INavigationQueryFilterInterface* Other) const { // @NOTE: not type safe, should be changed when // another filter type is introduced return FMemory::Memcmp(this, Other, sizeof(this)) == 0;
}
PVS-Studio warning: V579 The Memcmp function receives the pointer and its size as arguments. It is possibly a mistake. Inspect the third argument. pimplrecastnavmesh.cpp 172
Comparison functions usually call other comparison functions. At the same time one of the possible errors is that the reference/pointer is passed to the same object twice. Example:
x = memcmp(A, A, sizeof(T));
Here the object A will be compared with itself, which, is of course, has no sense.
We'll start with an error, found in the debugger GDB (C):
static int psymbol_compare (const void *addr1, const void *addr2, int length) { struct partial_symbol *sym1 = (struct partial_symbol *) addr1; struct partial_symbol *sym2 = (struct partial_symbol *) addr2; return (memcmp (&sym1->ginfo.value, &sym1->ginfo.value, // <= sizeof (sym1->ginfo.value)) == 0&& sym1->ginfo.language == sym2->ginfo.language&& PSYMBOL_DOMAIN (sym1) == PSYMBOL_DOMAIN (sym2)&& PSYMBOL_CLASS (sym1) == PSYMBOL_CLASS (sym2)&& sym1->ginfo.name == sym2->ginfo.name); }
PVS-Studio warning: V549 The first argument of 'memcmp' function is equal to the second argument. psymtab.c 1580
The code of CryEngineSDK project (C++):
inline bool operator != (const SEfResTexture &m) const { if (stricmp(m_Name.c_str(), m_Name.c_str()) != 0 || // <= m_TexFlags != m.m_TexFlags || m_bUTile != m.m_bUTile || m_bVTile != m.m_bVTile || m_Filter != m.m_Filter || m_Ext != m.m_Ext || m_Sampler != m.m_Sampler) return true; return false; }
PVS-Studio warning: V549 The first argument of 'stricmp' function is equal to the second argument. ishader.h 2089
The code of PascalABC.NET (C#):
private List<string> enum_consts = new List<string>(); public override bool IsEqual(SymScope ts) { EnumScope es = ts as EnumScope; if (es == null) return false; if (enum_consts.Count != es.enum_consts.Count) return false; for (int i = 0; i < es.enum_consts.Count; i++) if (string.Compare(enum_consts[i], this.enum_consts[i], true) != 0) return false; return true; }
PVS-Studio warning: V3038 The 'enum_consts[i]' argument was passed to 'Compare' method several times. It is possible that other argument should be passed instead. CodeCompletion SymTable.cs 2206
I'll give some explanation here. The error in the factual arguments of the Compare function:
string.Compare(enum_consts[i], this.enum_consts[i], true)
The thing is that enum_consts[i] and this.enum_consts[i are the same things. As I understand, a correct call should be like this:
string.Compare(es.enum_consts[i], this.enum_consts[i], true)
or
string.Compare(enum_consts[i], es.enum_consts[i], true)
Quite a common error in programming is when the same check is done twice. Example:
return A == B && C == D && // <= C == D && // <= E == F;
Two variants are possible in this case. The first is quite harmless: one comparison is redundant and can be simply removed. The second is worse: some other variables were to be compared, but a programmer made a typo.
In any case, such code deserves close attention. Let me scare you a little more, and show that this error can be found even in the code of GCC compiler (C):
static bool dw_val_equal_p (dw_val_node *a, dw_val_node *b) { .... case dw_val_class_vms_delta: return (!strcmp (a->v.val_vms_delta.lbl1, b->v.val_vms_delta.lbl1)&& !strcmp (a->v.val_vms_delta.lbl1, b->v.val_vms_delta.lbl1)); .... }
PVS-Studio warning: V501 There are identical sub-expressions '!strcmp(a->v.val_vms_delta.lbl1, b->v.val_vms_delta.lbl1)' to the left and to the right of the '&&' operator. dwarf2out.c 1428
The function strcmp is called twice with the same set of arguments.
The code of Unreal Engine 4 project (C++):
FORCEINLINE bool operator==(const FShapedGlyphEntryKey& Other) const { return FontFace == Other.FontFace&& GlyphIndex == Other.GlyphIndex // <=&& FontSize == Other.FontSize&& FontScale == Other.FontScale&& GlyphIndex == Other.GlyphIndex; // <= }
PVS-Studio warning: V501 There are identical sub-expressions 'GlyphIndex == Other.GlyphIndex' to the left and to the right of the '&&' operator. fontcache.h 139
The code of Serious Engine project (C++):
inline BOOL CValuesForPrimitive::operator==(....) { return ( (....) && (vfp_ptPrimitiveType == vfpToCompare.vfp_ptPrimitiveType) && .... (vfp_ptPrimitiveType == vfpToCompare.vfp_ptPrimitiveType) && .... );
PVS-Studio warning: V501 There are identical sub-expressions '(vfp_ptPrimitiveType == vfpToCompare.vfp_ptPrimitiveType)' to the left and to the right of the '&&' operator. worldeditor.h 580
The code of Oracle VM Virtual Box project (C++):
typedef struct SCMDIFFSTATE { .... bool fIgnoreTrailingWhite; bool fIgnoreLeadingWhite; .... } SCMDIFFSTATE; /* Pointer to a diff state. */ typedef SCMDIFFSTATE *PSCMDIFFSTATE; /* Compare two lines */ DECLINLINE(bool) scmDiffCompare(PSCMDIFFSTATE pState, ....) { .... if (pState->fIgnoreTrailingWhite // <= || pState->fIgnoreTrailingWhite) // <= return scmDiffCompareSlow(....); .... }
PVS-Studio warning: V501 There are identical sub-expressions 'pState->fIgnoreTrailingWhite' to the left and to the right of the '||' operator. scmdiff.cpp 238
The memcmp function returns the following values of int type:
Please note that '>0' can be any number, not only 1. These numbers can be: 2, 3, 100, 256, 1024, 5555, 65536 and so on. This means that this result cannot be placed to a variable of the char and short type. The high bits can be lost, which might violate the logic of program execution.
Also this means that the result cannot be compared with constants 1 or -1. In other words, it is wrong to write this:
if (memcmp(a, b, sizeof(T)) == 1) if (memcmp(x, y, sizeof(T)) == -1)
Correct comparisons:
if (memcmp(a, b, sizeof(T)) > 0) if (memcmp(a, b, sizeof(T)) < 0)
The danger of this code is that it may successfully work for a long time. The errors may start showing up when moving to a new platform or with the change of the compiler version.
The code of ReactOS project (C++):
HRESULT WINAPI CRecycleBin::CompareIDs(....) { .... return MAKE_HRESULT(SEVERITY_SUCCESS, 0, (unsigned short)memcmp(pidl1->mkid.abID, pidl2->mkid.abID, pidl1->mkid.cb)); }
PVS-Studio warning: V642 Saving the 'memcmp' function result inside the 'unsigned short' type variable is inappropriate. The significant bits could be lost breaking the program's logic. recyclebin.cpp 542
The code of Firebird project (C++):
SSHORT TextType::compare(ULONG len1, const UCHAR* str1, ULONG len2, const UCHAR* str2) { .... SSHORT cmp = memcmp(str1, str2, MIN(len1, len2)); if (cmp == 0) cmp = (len1 < len2 ? -1 : (len1 > len2 ? 1 : 0)); return cmp; }
PVS-Studio warning: V642 Saving the 'memcmp' function result inside the 'short' type variable is inappropriate. The significant bits could be lost breaking the program's logic. texttype.cpp 338
The code of CoreCLR project (C++):
bool operator( )(const GUID& _Key1, const GUID& _Key2) const { return memcmp(&_Key1, &_Key2, sizeof(GUID)) == -1; }
PVS-Studio warning: V698 Expression 'memcmp(....) == -1' is incorrect. This function can return not only the value '-1', but any negative value. Consider using 'memcmp(....) < 0' instead. sos util.cpp 142
The code of OpenToonz project (C++):
bool TFilePath::operator<(const TFilePath &fp) const { .... char differ; differ = _wcsicmp(iName.c_str(), jName.c_str()); if (differ != 0) return differ < 0 ? true : false; .... }
PVS-Studio warning: V642 Saving the '_wcsicmp' function result inside the 'char' type variable is inappropriate. The significant bits could be lost, breaking the program's logic. tfilepath.cpp 328
This error pattern is typical for C# programs. Sometimes in the comparison functions programmers write the type casting with the help of the as operator. The error is that inadvertently a programmer verifies against null not the new reference, but the original one. Let's take a look at a synthetic example:
ChildT foo = obj as ChildT; if (obj == null) return false; if (foo.zzz()) {}
The check if (obj == null) protects from the situation, if the obj variable contains a null reference. However, there is no protection from the case if it turns out that the as operator returns a null reference. The correct code should be like this:
ChildT foo = obj as ChildT; if (foo == null) return false; if (foo.zzz()) {}
Typically, this error occurs due to negligence of the programmer. Similar bugs are possible in the programs in C and C++, but I haven't found such a case in our error base.
The code of MonoDevelop project (C#):
public override bool Equals (object o) { SolutionItemReference sr = o as SolutionItemReference; if (o == null) return false; return (path == sr.path) && (id == sr.id); }
PVS-Studio warning: V3019 Possibly an incorrect variable is compared to null after type conversion using 'as' keyword. Check variables 'o', 'sr'. MonoDevelop.Core SolutionItemReference.cs 81
The code of CoreFX (C#):
public override bool Equals(object comparand) { CredentialHostKey comparedCredentialKey = comparand as CredentialHostKey; if (comparand == null) { // This covers also the compared == null case return false; } bool equals = string.Equals(AuthenticationType, comparedCredentialKey.AuthenticationType, .... .... }
PVS-Studio warning: V3019 Possibly an incorrect variable is compared to null after type conversion using 'as' keyword. Check variables 'comparand', 'comparedCredentialKey'. CredentialCache.cs 4007
The code of Roslyn project (C#):
public override bool Equals(object obj) { var d = obj as DiagnosticDescription; if (obj == null) return false; if (!_code.Equals(d._code)) return false; .... }
PVS-Studio warning: V3019 Possibly an incorrect variable is compared to null after type conversion using 'as' keyword. Check variables 'obj', 'd'. DiagnosticDescription.cs 201
The code of Roslyn (C#):
protected override bool AreEqual(object other) { var otherResourceString = other as LocalizableResourceString; return other != null && _nameOfLocalizableResource == otherResourceString._nameOfLocalizableResource && _resourceManager == otherResourceString._resourceManager && _resourceSource == otherResourceString._resourceSource && .... }
PVS-Studio warning: V3019 Possibly an incorrect variable is compared to null after type conversion using 'as' keyword. Check variables 'other', 'otherResourceString'. LocalizableResourceString.cs 121
The code of MSBuild project (C#):
public override bool Equals(object obj) { AssemblyNameExtension name = obj as AssemblyNameExtension; if (obj == null) // <= { return false; } .... }
PVS-Studio warning: V3019 Possibly an incorrect variable is compared to null after type conversion using 'as' keyword. Check variables 'obj', 'name'. AssemblyRemapping.cs 64
The code of Mono project (C#):
public override bool Equals (object o) { UrlMembershipCondition umc = (o as UrlMembershipCondition); if (o == null) // <= return false; .... return (String.Compare (u, 0, umc.Url, ....) == 0); // <= }
PVS-Studio warning: V3019 Possibly an incorrect variable is compared to null after type conversion using 'as' keyword. Check variables 'o', 'umc'. UrlMembershipCondition.cs 111
The code of Media Portal 2 project (C#):
public override bool Equals(object obj) { EpisodeInfo other = obj as EpisodeInfo; if (obj == null) return false; if (TvdbId > 0 && other.TvdbId > 0) return TvdbId == other.TvdbId; .... }
PVS-Studio warning: V3019 Possibly an incorrect variable is compared to null after type conversion using 'as' keyword. Check variables 'obj', 'other'. EpisodeInfo.cs 560
The code of NASA World Wind project (C#):
public int CompareTo(object obj) { RenderableObject robj = obj as RenderableObject; if(obj == null) // <= return 1; return this.m_renderPriority.CompareTo(robj.RenderPriority); }
PVS-Studio warning: V3019 Possibly an incorrect variable is compared to null after type conversion using 'as' keyword. Check variables 'obj', 'robj'. RenderableObject.cs 199
In some functions, collections of items are compared. Of course, different variant of the loops are used for its comparison. If a programmer writes the code inattentively, it's easy to mix something up, as it is with the comparison functions. Let's look at a few of these situations.
The code of Trans-Proteomic Pipeline (C++):
bool Peptide::operator==(Peptide& p) { .... for (i = 0, j = 0; i < this->stripped.length(), j < p.stripped.length(); i++, j++) { .... }
PVS-Studio warning: V521 Such expressions using the ',' operator are dangerous. Make sure the expression is correct. tpplib peptide.cpp 191
Note that the comma operator is used in the condition. The code is clearly incorrect, because the condition, written to the left of the coma is ignored. That is, the condition on the left is evaluated, but its result is not used in any way.
The code of Qt project (C++):
bool equals( class1* val1, class2* val2 ) const { ... size_t size = val1->size(); ... while ( --size >= 0 ){ if ( !comp(*itr1,*itr2) ) return false; itr1++; itr2++; } ... }
PVS-Studio warning: V547 Expression '-- size >= 0' is always true. Unsigned type value is always >= 0. QtCLucene arrays.h 154
The code of CLucene project (C++):
class Arrays { .... bool equals( class1* val1, class2* val2 ) const{ static _comparator comp; if ( val1 == val2 ) return true; size_t size = val1->size(); if ( size != val2->size() ) return false; _itr1 itr1 = val1->begin(); _itr2 itr2 = val2->begin(); while ( --size >= 0 ){ if ( !comp(*itr1,*itr2) ) return false; itr1++; itr2++; } return true; } .... }
PVS-Studio warning: V547 Expression '-- size >= 0' is always true. Unsigned type value is always >= 0. arrays.h 154
The code of Mono project (C#):
public override bool Equals (object obj) { .... for (int i=0; i < list.Count; i++) { bool found = false; for (int j=0; i < ps.list.Count; j++) { // <= if (list [i].Equals (ps.list [j])) { found = true; break; } } if (!found) return false; } return true; }
PVS-Studio warning: V3015 It is likely that a wrong variable is being compared inside the 'for' operator. Consider reviewing 'i' corlib-net_4_x PermissionSet.cs 607
Apparently, there is a typo here, and the variable j instead of i should be used in the nested loop:
for (int j=0; j < ps.list.Count; j++)
Quite often in the comparison functions a programmer has to write code of this kind:
if (GetA().x == GetB().x && GetA().y == GetB().y)
Intermediate variables are used to reduce the size of the conditions or for optimization:
Type A = GetA(); Type B = GetB(); if (A.x == B.x && A.y == B.y)
But inadvertently, a person sometimes makes a mistake and initializes temporary variables with the same value:
Type A = GetA(); Type B = GetA();
Now let's take a look at these errors in the code of real applications.
The code of LibreOffice project (C++):
bool CmpAttr( const SfxPoolItem& rItem1, const SfxPoolItem& rItem2) { .... bool bNumOffsetEqual = false; ::boost::optional<sal_uInt16> oNumOffset1 = static_cast<const SwFmtPageDesc&>(rItem1).GetNumOffset(); ::boost::optional<sal_uInt16> oNumOffset2 = static_cast<const SwFmtPageDesc&>(rItem1).GetNumOffset(); if (!oNumOffset1 && !oNumOffset2) { bNumOffsetEqual = true; } else if (oNumOffset1 && oNumOffset2) { bNumOffsetEqual = oNumOffset1.get() == oNumOffset2.get(); } else { bNumOffsetEqual = false; } .... }
PVS-Studio warning: V656 Variables 'oNumOffset1', 'oNumOffset2' are initialized through the call to the same function. It's probably an error or un-optimized code. Check lines: 68, 69. findattr.cxx 69
The code of Qt project (C++):
AtomicComparator::ComparisonResult IntegerComparator::compare(const Item &o1, const AtomicComparator::Operator, const Item &o2) const { const Numeric *const num1 = o1.as<Numeric>(); const Numeric *const num2 = o1.as<Numeric>(); if(num1->isSigned() || num2->isSigned()) .... }
PVS-Studio warning: V656 Variables 'num1', 'num2' are initialized through the call to the same function. It's probably an error or un-optimized code. Consider inspecting the 'o1.as < Numeric > ()' expression. Check lines: 220, 221. qatomiccomparators.cpp 221
A large amount of errors, cited previously can be called the consequences of sloppy Copy-Paste. They fell under some categories of the erroneous pattern and I decided that it would be logical to describe them in corresponding sections. However, I have several errors that have clearly appeared because of sloppy code copying, but I have no idea how to classify them. That's why I collected these errors here.
The code of CoreCLR project (C++):
int __cdecl Compiler::RefCntCmp(const void* op1, const void* op2) { .... if (weight1) { .... if (varTypeIsGC(dsc1->TypeGet())) { weight1 += BB_UNITY_WEIGHT / 2; } if (dsc1->lvRegister) { weight1 += BB_UNITY_WEIGHT / 2; } } if (weight1) { .... if (varTypeIsGC(dsc2->TypeGet())) { weight1 += BB_UNITY_WEIGHT / 2; // <= } if (dsc2->lvRegister) { weight2 += BB_UNITY_WEIGHT / 2; } } .... }
PVS-Studio warning: V778 Two similar code fragments were found. Perhaps, this is a typo and 'weight2' variable should be used instead of 'weight1'. clrjit lclvars.cpp 2702
The function was long that's why it is shortened for the article. If we examine the code of the function, we'll see that a part of the code was copied, but in one fragment a programmer forgot to replace the variable weight1 with weight2.
The code of WPF samples by Microsoft project (C#):
public int Compare(GlyphRun a, GlyphRun b) { .... if (aPoint.Y > bPoint.Y) // <= { return -1; } else if (aPoint.Y > bPoint.Y) // <= { result = 1; } else if (aPoint.X < bPoint.X) { result = -1; } else if (aPoint.X > bPoint.X) { result = 1; } .... }
PVS-Studio warning: V3003 The use of 'if (A) {...} else if (A) {...}' pattern was detected. There is a probability of logical error presence. Check lines: 418, 422. txtserializerwriter.cs 418
The code of PascalABC.NET project (C#):
public void CompareInternal(....) { .... else if (left is int64_const) CompareInternal(left as int64_const, right as int64_const); .... else if (left is int64_const) CompareInternal(left as int64_const, right as int64_const); .... }
PVS-Studio warning: V3003 The use of 'if (A) {...} else if (A) {...}' pattern was detected. There is a probability of logical error presence. Check lines: 597, 631. ParserTools SyntaxTreeComparer.cs 597
The code of SharpDevelop project (C#):
public int Compare(SharpTreeNode x, SharpTreeNode y) { .... if (typeNameComparison == 0) { if (x.Text.ToString().Length < y.Text.ToString().Length) return -1; if (x.Text.ToString().Length < y.Text.ToString().Length) return 1; } .... }
PVS-Studio warning: V3021 There are two 'if' statements with identical conditional expressions. The first 'if' statement contains method return. This means that the second 'if' statement is senseless NamespaceTreeNode.cs 87
The code of Coin3D (C++):
int SbProfilingData::operator == (const SbProfilingData & rhs) const { if (this->actionType != rhs.actionType) return FALSE; if (this->actionStartTime != rhs.actionStopTime) return FALSE; if (this->actionStartTime != rhs.actionStopTime) return FALSE; .... }
PVS-Studio warning: V649 There are two 'if' statements with identical conditional expressions. The first 'if' statement contains function return. This means that the second 'if' statement is senseless. Check lines: 1205, 1206. sbprofilingdata.cpp 1206
The code of Spring (C++):
bool operator < (const aiFloatKey& o) const {return mTime < o.mTime;} bool operator > (const aiFloatKey& o) const {return mTime < o.mTime;}
PVS-Studio warning: V524 It is odd that the body of '>' function is fully equivalent to the body of '<' function. assimp 3dshelper.h 470
And here is the last, particularly interesting code fragment that PVS-Studio analyzer found in MySQL project (C++).
static int rr_cmp(uchar *a,uchar *b) { if (a[0] != b[0]) return (int) a[0] - (int) b[0]; if (a[1] != b[1]) return (int) a[1] - (int) b[1]; if (a[2] != b[2]) return (int) a[2] - (int) b[2]; if (a[3] != b[3]) return (int) a[3] - (int) b[3]; if (a[4] != b[4]) return (int) a[4] - (int) b[4]; if (a[5] != b[5]) return (int) a[1] - (int) b[5]; // <= if (a[6] != b[6]) return (int) a[6] - (int) b[6]; return (int) a[7] - (int) b[7]; }
PVS-Studio warning: V525 The code containing the collection of similar blocks. Check items '0', '1', '2', '3', '4', '1', '6' in lines 680, 682, 684, 689, 691, 693, 695. sql records.cc 680
Most likely, a programmer wrote the first comparison, then the second and got bored. So he copied to the buffer a text block:
if (a[1] != b[1]) return (int) a[1] - (int) b[1];
A pasted it to the text of the program as many times as he needed. Then he changed indexes, but made a mistake in one place and got an incorrect comparison:
if (a[5] != b[5]) return (int) a[1] - (int) b[5];
Note. I discuss this error in more detail in my mini-book "The Ultimate Question of Programming, Refactoring, and Everything" (see a chapter "Don't do the compiler's job").
In C# the accepted practice is to implement the Equals methods in such a way, so that they correctly process a situation, if a null reference is passed as an argument. Unfortunately, not all the methods are implemented according to this rule.
The code of GitExtensions (C#):
public override bool Equals(object obj) { return GetHashCode() == obj.GetHashCode(); // <= }
PVS-Studio warning: V3115 Passing 'null' to 'Equals(object obj)' method should not result in 'NullReferenceException'. Git.hub Organization.cs 14
The code of PascalABC.NET project (C#):
public override bool Equals(object obj) { var rhs = obj as ServiceReferenceMapFile; return FileName == rhs.FileName; }
PVS-Studio warning: V3115 Passing 'null' to 'Equals' method should not result in 'NullReferenceException'. ICSharpCode.SharpDevelop ServiceReferenceMapFile.cs 31
The code of G3D Content Pak project (C++):
bool Matrix4::operator==(const Matrix4& other) const { if (memcmp(this, &other, sizeof(Matrix4) == 0)) { return true; } ... }
PVS-Studio warning: V575 The 'memcmp' function processes '0' elements. Inspect the 'third' argument. graphics3D matrix4.cpp 269
One closing bracket is put incorrectly. As a result, the amount of bites compared is evaluated by the statement sizeof(Matrix4) == 0. The size of any class is more than 0, which means that the result of the expression is 0. Thus, 0 bites get compared.
Correct variant:
if (memcmp(this, &other, sizeof(Matrix4)) == 0) {
The code of Wolfenstein 3D project (C++):
inline int operator!=( quat_t a, quat_t b ) { return ( ( a.x != b.x ) || ( a.y != b.y ) || ( a.z != b.z ) && ( a.w != b.w ) ); }
PVS-Studio warning: V648 Priority of the '&&' operation is higher than that of the '||' operation. math_quaternion.h 167
Apparently, in one fragment the && operator was accidentally written instead of ||.
The code of FlightGear project (C):
static int tokMatch(struct Token* a, struct Token* b) { int i, l = a->strlen; if(!a || !b) return 0; .... }
PVS-Studio warning: V595 The 'a' pointer was utilized before it was verified against nullptr. Check lines: 478, 479. codegen.c 478
If we pass NULL as the first argument to the function, we'll get null pointer dereference, although the programmer wanted the function to return 0.
The code of WinMerge project (C++):
int TimeSizeCompare::CompareFiles(int compMethod, const DIFFITEM &di) { UINT code = DIFFCODE::SAME; ... if (di.left.size != di.right.size) { code &= ~DIFFCODE::SAME; code = DIFFCODE::DIFF; } ... }
PVS-Studio warning: V519 The 'code' variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 79, 80. Merge timesizecompare.cpp 80
The code of ReactOS project (C++):
#define IsEqualGUID(rguid1, rguid2) \ (!memcmp(&(rguid1), &(rguid2), sizeof(GUID))) static int ctl2_find_guid(....) { MSFT_GuidEntry *guidentry; ... if (IsEqualGUID(guidentry, guid)) return offset; ... }
PVS-Studio warning: V512 A call of the 'memcmp' function will lead to underflow of the buffer 'guidentry'. oleaut32 typelib2.c 320
A pointer is written here as the first argument. As a result, the address of the pointer gets evaluated, which has no sense.
Correct variant:
if (IsEqualGUID(*guidentry, guid)) return offset;
The code of IronPython and IronRuby project (C#):
public static bool Equals(float x, float y) { if (x == y) { return !Single.IsNaN(x); } return x == y; }
PVS-Studio warning: V3024 An odd precise comparison: x == y. Consider using a comparison with defined precision: Math.Abs(A - B) < Epsilon. FloatOps.cs 1048
It's not clear what is the point of a special check against NaN here. If the condition (x == y) is true, it means that both x and y and different from NaN, because NaN isn't equal to any other value, including itself. It seems that the check against NaN is just not necessary, and the code can be shortened to:
public static bool Equals(float x, float y) { return x == y; }
The code of Mono project (C#):
public bool Equals (CounterSample other) { return rawValue == other.rawValue && baseValue == other.counterFrequency && // <= counterFrequency == other.counterFrequency && // <= systemFrequency == other.systemFrequency && timeStamp == other.timeStamp && timeStamp100nSec == other.timeStamp100nSec && counterTimeStamp == other.counterTimeStamp && counterType == other.counterType; }
PVS-Studio warning: V3112 An abnormality within similar comparisons. It is possible that a typo is present inside the expression 'baseValue == other.counterFrequency'. System-net_4_x CounterSample.cs 139
Looking through all the errors, it seems miraculous that all these programs generally work. Indeed, the comparison functions do a very important and responsible task in program.
There are several explanations of why these programs work despite these errors:
I demonstrated how many errors can be found in the comparison functions. It follows that the efficiency of these functions should be checked with unit-tests by all means.
It is really necessary to write unit-tests for the comparison operators, for Equals functions and so on.
I am quite sure that there was such an understanding among programmers before reading this article, that unit tests for such functions is extra work and they won't detect any errors anyway: the comparison functions are just so simple at the first glance... Well, now I showed the horror that can hide in them.
Code reviews and using static analysis tools would also be a great help.
In this article we mentioned a large amount of big-name projects that are developed by highly qualified experts. These projects are thoroughly tested using different methodologies. Still, it didn't stop PVS-Studio from finding errors in them. This shows that PVS-Studio can become a nice complement to other methodologies used to improve the quality and reliability of the code.
Download [1.9KB]
As solid-state drives (SSDs) become more affordable, cloud providers are working to provide high-performance, highly reliable SSD-based storage for their customers. Red Hat Ceph* Storage, an open source scale-out storage solution, faces increasing demand from customers who wish to use SSDs in Ceph Storage to build high-performance storage solutions for their clouds.
The disruptive Intel® Optane™ Solid State Drive based on 3D XPoint™ technology fills the performance gap between DRAM and NAND-based SSDs. At the same time, Intel® 3D NAND TLC is reducing the cost gap between SSDs and traditional spindle hard drives, making all-flash storage an affordable option.
This article presents three Ceph Storage all-flash storage system reference designs, and provides Ceph Storage performance test results on the first Intel Optane and P4500 TLC NAND based all-flash cluster. This cluster delivers multi-million IOPS with extremely low latency as well as increased storage density with competitive dollar-per-gigabyte costs. It also shares Ceph Storage BlueStore tunings and optimizations, especially rocksdb tunings to mitigate the impact of compaction.
Several motivations are driving the development of Ceph-based all-flash storage systems. Cloud storage providers (CSPs) are struggling to deliver performance at increasingly massive scale. A common scenario is to build an Amazon EBS-like service for an OpenStack*-based public/private cloud, leading many CSPs to adopt Ceph-based all-flash storage systems. Meanwhile, there is strong demand to run enterprise applications in the cloud. For example, customers are adapting OLTP workloads to run on Ceph Storage when they migrate from traditional enterprise storage solutions. In addition to the major goal of leveraging the multi-purpose Ceph all-flash storage cluster to reduce TCO, performance is an important factor for these OLTP workloads. Moreover, with the steadily declining price of SSDs and efficiency-boosting technologies like deduplication and compression, an all-flash array (AFA) is becoming increasingly acceptable.
Intel® Optane™ technology provides an unparalleled combination of high throughput, low latency, high quality of service, and high endurance. It is a unique combination of 3D XPoint™ Memory Media, Intel Memory and Storage Controllers, Intel Interconnect IP and Intel® software1. Together these building blocks deliver a revolutionary leap forward in decreasing latency and accelerating systems for workloads demanding large capacity and fast storage.
Intel 3D NAND technology improves regular two-dimensional storage by stacking storage cells to increase capacity through higher density, lower cost per gigabyte, and offers the reliability, speed, and performance expected of solid-state memory3. It offers a cost-effective replacement for traditional hard-disk drives (HDDs) to help customers accelerate user experiences, improve the performance of apps and services across segments, and also reduce IT costs.
Based on different usage cases and application characteristics, Intel proposed three reference architectures (RAs) for Ceph-based all-flash array (AFA).
Standard configuration is ideally suited for throughput optimized workloads that need high-capacity storage with good performance. We recommend using NVMe*/PCIe* SSD for journal and caching to achieve the best performance while balancing the cost. Table 1 describes the RA using 1x Intel® SSD DC P4600 Series as a journal or BlueStore* rocksdb write-ahead log (WAL) device, 12x up to 4 TB HDD as data drive.
NVMe/PCIe SSD for journal and caching, 12x HDD for data, Intel® Xeon® processor, Intel® Network Interface Card
Example: 1x 1.6 TB Intel SSD DC P4600 as a journal, Intel® Cache Acceleration Software, 12 HDDs, Intel® Xeon® processor E5-2650 v4 .
Table 1. Standard configuration.
Ceph Storage Node configuration – Standard | |
---|---|
CPU | Intel® Xeon® processor E5-2650 v4 |
Memory | 64 GB |
NIC | Single 10Gb E, Intel® 82599 10 Gigabit Ethernet Controller or Intel® Ethernet Controller X550 |
Storage | Data: 12 x 4 TB HDD |
Caching Software | Intel® Cache Acceleration Software 3.0, option: Intel® Rapid Storage Technology enterprise/MD4.3; open source cache-like bache/flashcache |
The TCO-optimized configuration provides the best possible performance for workloads that need higher performance, especially for throughput, IOPS, and SLAs with medium storage capacity requirements, leveraging a mixed of NVMe and SATA SSDs.
Table 2. TCO optimized configuration
Ceph Storage node –TCO Optimized | |
---|---|
CPU | Intel® Xeon® processor E5-2690 v4 |
Memory | 128 GB |
NIC | Dual 10GbE (20 GB), Intel® 82599 10 Gigabit Ethernet Controller |
Storage | Data: 4x Intel® SSD DC P4500 4, 8, or 16 TB or Intel DC SATA SSDs Journal or WAL: 1x Intel® SSD DC P4600 Series 1.6 TB |
The IOPS-optimized configuration provided best performance (throughput and latency) with Intel Optane Solid State Drives as Journal (FileStore) and WAL device (BlueStore) for a standalone Ceph cluster.
Table 3. IOPS optimized configuration
Ceph* Storage node –IOPS optimized | |
---|---|
CPU | Intel® Xeon® processor E5-2699 v4 |
Memory | >= 128 GB |
NIC | 2x 40GbE (80 Gb), 4x Dual 10GbE (800 Gb), Intel® Ethernet Converged Network Adapter X710 family |
Storage | Data: 4x Intel® SSD DC P4500 4, 8, or 16 TB Journal or WAL : 1x Intel® Optane™ SSD DC P4800X 375 GB |
This section presents a performance evaluation of the IOPS-optimized configuration based on Ceph BlueStore.
The test system described in Table 4 consisted of five Ceph storage servers, each fitted with two Intel® Xeon® processors E5-2699 v4 CPUs and 128 GB memory, plus 1x Intel® SSD DC P3700 2TB as a BlueStore WAL device and x 4 T Intel® SSD DC P3520 2TB as a data drive, and 1x Intel® Ethernet Converged Network Adapters X710 NIC 40 Gb NIC, two ports bonding together through bonding mode 6, used as separate cluster and public network for Ceph, system topology described in Figure 1. The test system also consisted of 5 client nodes, each fitted with two Intel Xeon processors E5-2699 v4 and 64 GB memory and 1x Intel Ethernet Converged Network Adapters X710 NIC 40 Gb NIC, two ports bonding together through bonding mode 6.
Ceph 12.0.0 (Luminous dev) was used, and each Intel SSD DC P3520 Series runs 4 OSD daemons. The rbd pool used for the testing was configured with 2 replica.
Table 4. System configuration.
Ceph Storage node – IOPS optimized | |
---|---|
CPU | Intel® Xeon® processor E5-2699 v4 2.20 GHz |
Memory | 128 GB |
NIC | 1x 40 G Intel® Ethernet Converged Network Adapters X710, two ports bonding mode 6 |
Disks | 1x Intel® SSD DC P3700 (2T) + 4x Intel® SSD DC P3520 2 TB |
Software configuration | Ubuntu* 14.04, Ceph 12.0.0 |
Figure 1. Cluster topology.
To simulate a typical usage scenario, four test patterns were selected using fio with librbd. It consisted of 4K random read and write, and 64K sequential read and write. For each pattern, the throughput (IOPS or bandwidth) was measured as performance metrics with the number of volumes scaling; the volume size was 30 GB. To get stable performance, the volumes were pre-allocated to bypass the performance impact of thin-provision. OSD page cache was dropped before each run to eliminate page cache impact. For each test case, fio was configured with a 100 seconds warm up and 300 seconds data collection. Detail fio testing parameters were included in the software configuration part.
Table 5 shows the promising performance after tuning on this five-node cluster. 64K sequential read and write throughput is 5630 MB/s and 4200 MB/s respectively (maximums with the Intel Ethernet Converged Network Adapters X710 NIC in bonding mode 6). 4 K random read throughput is 1312K IOPS with 1ms average latency, while 4 KB random write throughput is 331K IOPS with 4.8 ms average latency. The performance measured in the testing was roughly within expectations, unless a regression of 64K sequential write tests compared with previous Ceph releases, which requires further investigation and optimization.
Table 5. Performance overview.
Pattern | Throughput | Average Latency |
---|---|---|
64KB Sequential Write | 4200 MB/s | 18.9ms |
64KB Sequential Read | 5630 MB/s | 17.7ms |
4KB Random Write | 331K IOPS | 4.8ms |
4KB Random Read | 1312K IOPS | 1.2ms |
Figures 2 to 5 show the graph of throughput for 4K random and 64K sequential workloads with different number of volumes, each fio was running in the volume with 16 queue depth.
Ceph demonstrated excellent 4K random read performance on the all-flash array reference architecture, as the total number of volumes increased from 1 to 100, the total 4K random read IOPS peaked around 1310 K IOPS, with an average latency around 1.2 ms. The total 4K random write IOPS peaked around 330K IOPS, with an average latency around 4.8 ms.
Figure 2. 4K Random read performance.
Figure 3. 4K random write performance load line.
For 64K sequential read and write, as the total number of volumes increased from 1 to 100, the sequential read throughput peaked around 5630 MB/s, while sequential write peaked around 4200 MB/s. The sequential write throughput was lower than the previous Ceph release (11.0.2). It requires further investigation and optimization; stay tuned for further updates.
Figure 4. 64K sequential read throughput
Figure 5. 64K sequential write throughput
Fig 6 shows the latency comparison for 4K random write workloads with 1x Intel® SSD DC P3700 series 2.0TB and 1x Intel® Optane™ SSD DC P4800X series 375 GB drive as rocksdb & WAL device. The results proved with the Intel® Optane™ SSD DC P4800X series 375 GB SSD as rocksdb and WAL drive in Ceph BlueData, the latency was significantly reduced: a 226% reduction in 99.99% latency.
Figure 6. 4K random read and 4K random write latency comparison
Ceph is becoming one of most open source scale-out storage solutions, and there is a growing demands in build Ceph based high-performance all-flash array storage solutions for their clouds. We proposed three different reference architecture configurations targeting for different usage scenarios. The results of the testing that simulated different workload pattern demonstrated that a Ceph all-flash system could deliver very high performance with excellent latency.
Take 4K random read for example.
[global] direct=1 time_based [fiorbd-randread-4k-qd16-30g-100-300-rbd] rw=randread bs=4k iodepth=16 ramp_time=100 runtime=300 ioengine=rbd clientname=${RBDNAME} pool=${POOLNAME} rbdname=${RBDNAME} iodepth_batch_submit=1 iodepth_batch_complete=1 norandommap
This sample source code is released under the Intel Sample Source Code License Agreement.
This page provides links to the current ways to get the Intel® performance library: Intel® Math Kernel Library, Intel® Integrated Performance Primitives, Intel® Data Analytics Acceleration Library( Intel® MKL/IPP/DAAL)
https://software.intel.com/en-us/intel-parallel-studio-xe
https://software.intel.com/en-us/system-studio
The article provide the version information of Intel® performance library include in the bundles product: https://software.intel.com/en-us/articles/which-version-of-the-intel-ipp-intel-mkl-and-intel-tbb-libraries-are-included-in-the-intel
• Free standalone access through separated product main page (Intel® MKL/IPP/DAAL)
https://software.intel.com/en-us/mkl
https://software.intel.com/en-us/intel-ipp
https://software.intel.com/en-us/intel-daal
Only for Intel® MKL
Perhaps, readers remember my article titled "Last line effect". It describes a pattern I've once noticed: in most cases programmers make an error in the last line of similar text blocks. Now I want to tell you about a new interesting observation. It turns out that programmers tend to make mistakes in functions comparing two objects. This statement looks implausible; however, I'll show you a great number of examples of errors that may be shocking to a reader. So, here is a new research, it will be quite amusing and scary.
Here is my statement: programmers quite often make mistakes in rather simple functions that are meant to compare two objects. This claim is based on the experience of our team in checking a large number of open source projects in C, C++ and C#.
The functions we are going to consider here are IsEqual, Equals, Compare, AreEqual and so on or overloaded operators as ==, !=.
I noticed that when writing articles, very often I come across errors related to the comparison functions. I decided to explore this question in detail and examined the base of errors we found. I did a search of functions throughout the base containing words Cmp, Equal, Compare and such. The result was very impressive and shocking.
In fact this story is similar to the one we had when writing the article "Last line effect". Similarly, I noticed an anomaly and decided to explore it more carefully. Unfortunately, unlike the aforementioned article, I don't know how to bring statistics here and which figures to provide. Perhaps, later I'll come up with a solution with the statistics. At this point I am guided by intuition and can only share my feelings. They see that there are a lot of errors in the comparison functions and I am sure, you will get the same feeling when you see that huge amount of truly impressive examples.
For a moment let's go back to the article "Last line effect". By the way, if you haven't read it, I suggest taking a break and looking at it. There is a more detailed analysis of this topic: "The last line effect explained"
In general, we can conclude that the cause of the errors in the last lined is related to the fact that the developer has already mentally moved to the new lines/tasks instead of focusing on the completion of the current fragment. As a result - when writing similar blocks of text, there is a higher probability that a programmer will make an error in the last one.
I believe that in the case of writing a comparison function, a developer in general often don't focus on it, considering it to be too trivial. In other words, he writes the code automatically, without thinking over it. Otherwise, it is not clear how one can make an error like this:
bool IsLuidsEqual(LUID luid1, LUID luid2) { return (luid1.LowPart == luid2.LowPart) && (luid2.HighPart == luid2.HighPart); }
PVS-Studio analyzer detected this error in the code of RunAsAdmin Explorer Shim (C++) project: V501 There are identical sub-expressions to the left and to the right of the '==' operator: luid2.HighPart == luid2.HighPart RAACommon raacommonfuncs.cpp 1511
A typo. In the second line it should be: luid1.HighPart == luid2.HighPart.
The code is very simple. Apparently, the simplicity of code spoils everything. A programmer immediately thinks of the task to write such a function as standard and uninteresting. He instantly thinks of the way to write the function and he has just to implement the code. This is a routine, but unfortunately an inevitable process to start writing more important, complex and interesting code. He is already thinking about the new task... and as a result - makes an error.
In addition, programmers rarely write unit tests for such functions. Again the simplicity of these functions prevents from it. It seems that it would be too much to test them, as these functions are simple and repetitive. A person has written hundreds of such functions in his life, can he make an error in another function? Yes, he can and he does.
I would also like to note that we aren't talking about code of students who are just learning to program. We are talking about bugs in the code of such projects as GCC, Qt, GDB, LibreOffice, Unreal Engine, CryEngine 4 V Chromium, MongoDB, Oracle VM Virtual Box, FreeBSD, WinMerge, the CoreCLR, MySQL, Mono, CoreFX, Roslyn, MSBuild, etc. It's all very serious.
We are going to have a look at so many diverse examples that it would be scary to sleep at night.
All errors in comparison functions will be divided into several patterns. In the article we'll be talking about errors in projects in C, C++ and C#, but it makes no sense to separate these languages, as most of the patterns are similar for different languages.
Very often in the comparison functions there is a need to make such checks:
Sometimes programmers think that is more elegant to use the same operator <, but to switch the variables.
However, due to the inattentiveness, we get such checks:
In fact, one and the same comparison is done twice here. Perhaps, it's not clear what it is about here, but we'll get to the practical examples and it'll all become clearer.
string _server; .... bool operator<( const ServerAndQuery& other ) const { if ( ! _orderObject.isEmpty() ) return _orderObject.woCompare( other._orderObject ) < 0; if ( _server < other._server ) return true; if ( other._server > _server ) return false; return _extra.woCompare( other._extra ) < 0; }
PVS-Studio analyzer detected this error in the code of MongoDB (C++): V581 The conditional expressions of the 'if' operators situated alongside each other are identical. Check lines: 44, 46. parallel.h 46
This condition:
if ( other._server > _server )
Will always be false, as the same check was done two lines before. Correct code variant:
if ( _server < other._server ) return true; if ( other._server < _server ) return false;
This error was detected in the code of Chromium project (C++):
enum ContentSettingsType; struct EntryMapKey { ContentSettingsType content_type; ... }; bool OriginIdentifierValueMap::EntryMapKey::operator<( const OriginIdentifierValueMap::EntryMapKey& other) const { if (content_type < other.content_type) return true; else if (other.content_type > content_type) return false; return (resource_identifier < other.resource_identifier); }
PVS-Studio warning: V517 The use of 'if (A) {...} else if (A) {...}' pattern was detected. There is a probability of logical error presence. Check lines: 61, 63. browser content_settings_origin_identifier_value_map.cc 61
That was a C++ example, now it's C# turn. The next error was found in the code of IronPython and IronRuby (C#).
public static int Compare(SourceLocation left, SourceLocation right) { if (left < right) return -1; if (right > left) return 1; return 0; }
PVS-Studio warning (C#): V3021 There are two 'if' statements with identical conditional expressions. The first 'if' statement contains method return. This means that the second 'if' statement is senseless. SourceLocation.cs 156
I think there is no need in explanation.
Note. For C# there was just one example of an error, but for C++ - two. In general, there will be less bugs in the C# code, than for C/C++. But I do not recommend rushing to the conclusion that C# is much safer. The thing is that PVS-Studio analyzer has only recently learned to check C# code relatively recently, and we have just checked less projects written in C#, than in C and C++.
The comparison functions usually consist of successive comparisons of structure/class members. This code tends to be more erronreous, when the member of the class starts being compared with itself. I can specify two subtypes of errors.
In the first case, a programmer forgets to specify the name of the object and writes in the following way:
return m_x == foo.m_x && m_y == m_y && // <= m_z == foo.m_z; In the second case, the same name of the object is written. return zzz.m_x == foo.m_x && zzz.m_y == zzz.m_y && // <= zzz.m_z == foo.m_z;
Let's take a closer look at practical examples of this pattern. Pay attention that incorrect comparison often occurs in the last block of similar code blocks, which reminds us of the "last line effect" again.
The error is found in the code of Unreal Engine 4 (C++) project:
bool Compare(const FPooledRenderTargetDesc& rhs, bool bExact) const { .... return Extent == rhs.Extent&& Depth == rhs.Depth&& bIsArray == rhs.bIsArray&& ArraySize == rhs.ArraySize&& NumMips == rhs.NumMips&& NumSamples == rhs.NumSamples&& Format == rhs.Format&& LhsFlags == RhsFlags&& TargetableFlags == rhs.TargetableFlags&& bForceSeparateTargetAndShaderResource == rhs.bForceSeparateTargetAndShaderResource&& ClearValue == rhs.ClearValue&& AutoWritable == AutoWritable; // <= }
PVS-Studio warning: V501 There are identical sub-expressions to the left and to the right of the '==' operator: AutoWritable == AutoWritable rendererinterface.h 180
The code of Samba (C) project:
static int compare_procids(const void *p1, const void *p2) { const struct server_id *i1 = (struct server_id *)p1; const struct server_id *i2 = (struct server_id *)p2; if (i1->pid < i2->pid) return -1; if (i2->pid > i2->pid) return 1; return 0; }
PVS-Studio warning: V501 There are identical sub-expressions to the left and to the right of the '>' operator: i2->pid > i2->pid brlock.c 1901
The code of MongoDB (C++) project:
bool operator==(const MemberCfg& r) const { .... return _id==r._id && votes == r.votes && h == r.h && priority == r.priority && arbiterOnly == r.arbiterOnly && slaveDelay == r.slaveDelay && hidden == r.hidden && buildIndexes == buildIndexes; // <= }
PVS-Studio warning: V501 There are identical sub-expressions to the left and to the right of the '==' operator: buildIndexes == buildIndexes rs_config.h 101
The code of Geant4 Software (C++) project:
inline G4bool G4FermiIntegerPartition:: operator==(const G4FermiIntegerPartition& right) { return (total == right.total && enableNull == enableNull && // <= partition == right.partition); }
PVS-Studio warning: V501 There are identical sub-expressions to the left and to the right of the '==' operator: enableNull == enableNull G4hadronic_deex_fermi_breakup g4fermiintegerpartition.icc 58
The code of LibreOffice (C++) project:
class SvgGradientEntry { .... bool operator==(const SvgGradientEntry& rCompare) const { return (getOffset() == rCompare.getOffset()&& getColor() == getColor() // <=&& getOpacity() == getOpacity()); // <= } .... }
PVS-Studio warning: V501 There are identical sub-expressions to the left and to the right of the '==' operator: getColor() == getColor() svggradientprimitive2d.hxx 61
The code of Chromium (C++) project:
bool FileIOTest::MatchesResult(const TestStep& a, const TestStep& b) { .... return (a.data_size == a.data_size && // <= std::equal(a.data, a.data + a.data_size, b.data)); }
PVS-Studio warning: V501 There are identical sub-expressions to the left and to the right of the '==' operator: a.data_size == a.data_size cdm_file_io_test.cc 367
The code of FreeCAD (C++) project:
bool FaceTypedBSpline::isEqual(const TopoDS_Face &faceOne, const TopoDS_Face &faceTwo) const { .... if (surfaceOne->IsURational() != surfaceTwo->IsURational()) return false; if (surfaceTwo->IsVRational() != // <= surfaceTwo->IsVRational()) // <= return false; if (surfaceOne->IsUPeriodic() != surfaceTwo->IsUPeriodic()) return false; if (surfaceOne->IsVPeriodic() != surfaceTwo->IsVPeriodic()) return false; if (surfaceOne->IsUClosed() != surfaceTwo->IsUClosed()) return false; if (surfaceOne->IsVClosed() != surfaceTwo->IsVClosed()) return false; if (surfaceOne->UDegree() != surfaceTwo->UDegree()) return false; if (surfaceOne->VDegree() != surfaceTwo->VDegree()) return false; .... }
PVS-Studio warning: V501 There are identical sub-expressions 'surfaceTwo->IsVRational()' to the left and to the right of the '!=' operator. modelrefine.cpp 780
The code of Serious Engine (C++) project:
class CTexParams { public: inline BOOL IsEqual( CTexParams tp) { return tp_iFilter == tp.tp_iFilter && tp_iAnisotropy == tp_iAnisotropy && // <= tp_eWrapU == tp.tp_eWrapU && tp_eWrapV == tp.tp_eWrapV; }; .... };
PVS-Studio warning: V501 There are identical sub-expressions to the left and to the right of the '==' operator: tp_iAnisotropy == tp_iAnisotropy gfx_wrapper.h 180
The code of Qt (C++) project:
inline bool qCompare(QImage const &t1, QImage const &t2, ....) { .... if (t1.width() != t2.width() || t2.height() != t2.height()) { .... }
PVS-Studio warning: V501 There are identical sub-expressions to the left and to the right of the '!=' operator: t2.height() != t2.height() qtest_gui.h 101
The code of FreeBSD (C) project:
static int compare_sh(const void *_a, const void *_b) { const struct ipfw_sopt_handler *a, *b; a = (const struct ipfw_sopt_handler *)_a; b = (const struct ipfw_sopt_handler *)_b; .... if ((uintptr_t)a->handler < (uintptr_t)b->handler) return (-1); else if ((uintptr_t)b->handler > (uintptr_t)b->handler) // <= return (1); return (0); }
PVS-Studio warning: V501 There are identical sub-expressions '(uintptr_t) b->handler' to the left and to the right of the '>' operator. ip_fw_sockopt.c 2893
The code of Mono (C#) project:
static bool AreEqual (VisualStyleElement value1, VisualStyleElement value2) { return value1.ClassName == value1.ClassName && // <= value1.Part == value2.Part && value1.State == value2.State; }
PVS-Studio warning: V3001 There are identical sub-expressions 'value1.ClassName' to the left and to the right of the '==' operator. ThemeVisualStyles.cs 2141
The code of Mono (C#) project:
public int ExactInference (TypeSpec u, TypeSpec v) { .... var ac_u = (ArrayContainer) u; var ac_v = (ArrayContainer) v; .... var ga_u = u.TypeArguments; var ga_v = v.TypeArguments; .... if (u.TypeArguments.Length != u.TypeArguments.Length) // <= return 0; .... }
PVS-Studio warning: V3001 There are identical sub-expressions 'u.TypeArguments.Length' to the left and to the right of the '!=' operator. generic.cs 3135
The code of MonoDevelop (C#) project:
Accessibility DeclaredAccessibility { get; } bool IsStatic { get; } private bool MembersMatch(ISymbol member1, ISymbol member2) { if (member1.Kind != member2.Kind) { return false; } if (member1.DeclaredAccessibility != // <=1 member1.DeclaredAccessibility // <=1 || member1.IsStatic != member1.IsStatic) // <=2 { return false; } if (member1.ExplicitInterfaceImplementations().Any() || member2.ExplicitInterfaceImplementations().Any()) { return false; } return SignatureComparer .HaveSameSignatureAndConstraintsAndReturnTypeAndAccessors( member1, member2, this.IsCaseSensitive); }
PVS-Studio warning: V3001 There are identical sub-expressions 'member1.IsStatic' to the left and to the right of the '!=' operator. CSharpBinding AbstractImplementInterfaceService.CodeAction.cs 545
The code of Haiku (C++) project:
int __CORTEX_NAMESPACE__ compareTypeAndID(....) { int retValue = 0; .... if (lJack && rJack) { if (lJack->m_jackType < lJack->m_jackType) // <= { return -1; } if (lJack->m_jackType == lJack->m_jackType) // <= { if (lJack->m_index < rJack->m_index) { return -1; } else { return 1; } } else if (lJack->m_jackType > rJack->m_jackType) { retValue = 1; } } return retValue; }
PVS-Studio warning: V501 There are identical sub-expressions to the left and to the right of the '<' operator: lJack->m_jackType < lJack->m_jackType MediaJack.cpp 783
Just below there is exactly the same error. As I understand, in both cases a programmer forgot to replace lJack with rJack.
The code of CryEngine V (C++) project:
bool CompareRotation(const Quat& q1, const Quat& q2, float epsilon) { return (fabs_tpl(q1.v.x - q2.v.x) <= epsilon)&& (fabs_tpl(q1.v.y - q2.v.y) <= epsilon)&& (fabs_tpl(q2.v.z - q2.v.z) <= epsilon) // <=&& (fabs_tpl(q1.w - q2.w) <= epsilon); }
PVS-Studio warning: V501 There are identical sub-expressions to the left and to the right of the '-' operator: q2.v.z - q2.v.z entitynode.cpp 93
This type of error occurs in programs written in C and C++ and is caused by incorrect use of the sizeof operator. The error in evaluating not the size of the object, but the size of the pointer. Example:
T *a = foo1(); T *b = foo2(); x = memcmp(a, b, sizeof(a));
Instead of the size of the T structure, a size of the pointer gets evaluated. The size of the pointer depends on the used data model, but usually it is 4 or 8. As a result, more or less bites in the memory get compared than take the structure.
Correct variant of the code:
x = memcmp(a, b, sizeof(T));
or
x = memcmp(a, b, sizeof(*a));
Now let's move on to the practical part. Here is how such a bug looks in the code of CryEngine V (C++) code:
bool operator==(const SComputePipelineStateDescription& other) const { return 0 == memcmp(this, &other, sizeof(this)); }
PVS-Studio warning: V579 The memcmp function receives the pointer and its size as arguments. It is possibly a mistake. Inspect the third argument. graphicspipelinestateset.h 58
The code of Unreal Engine 4 project (C++):
bool FRecastQueryFilter::IsEqual( const INavigationQueryFilterInterface* Other) const { // @NOTE: not type safe, should be changed when // another filter type is introduced return FMemory::Memcmp(this, Other, sizeof(this)) == 0;
}
PVS-Studio warning: V579 The Memcmp function receives the pointer and its size as arguments. It is possibly a mistake. Inspect the third argument. pimplrecastnavmesh.cpp 172
Comparison functions usually call other comparison functions. At the same time one of the possible errors is that the reference/pointer is passed to the same object twice. Example:
x = memcmp(A, A, sizeof(T));
Here the object A will be compared with itself, which, is of course, has no sense.
We'll start with an error, found in the debugger GDB (C):
static int psymbol_compare (const void *addr1, const void *addr2, int length) { struct partial_symbol *sym1 = (struct partial_symbol *) addr1; struct partial_symbol *sym2 = (struct partial_symbol *) addr2; return (memcmp (&sym1->ginfo.value, &sym1->ginfo.value, // <= sizeof (sym1->ginfo.value)) == 0&& sym1->ginfo.language == sym2->ginfo.language&& PSYMBOL_DOMAIN (sym1) == PSYMBOL_DOMAIN (sym2)&& PSYMBOL_CLASS (sym1) == PSYMBOL_CLASS (sym2)&& sym1->ginfo.name == sym2->ginfo.name); }
PVS-Studio warning: V549 The first argument of 'memcmp' function is equal to the second argument. psymtab.c 1580
The code of CryEngineSDK project (C++):
inline bool operator != (const SEfResTexture &m) const { if (stricmp(m_Name.c_str(), m_Name.c_str()) != 0 || // <= m_TexFlags != m.m_TexFlags || m_bUTile != m.m_bUTile || m_bVTile != m.m_bVTile || m_Filter != m.m_Filter || m_Ext != m.m_Ext || m_Sampler != m.m_Sampler) return true; return false; }
PVS-Studio warning: V549 The first argument of 'stricmp' function is equal to the second argument. ishader.h 2089
The code of PascalABC.NET (C#):
private List<string> enum_consts = new List<string>(); public override bool IsEqual(SymScope ts) { EnumScope es = ts as EnumScope; if (es == null) return false; if (enum_consts.Count != es.enum_consts.Count) return false; for (int i = 0; i < es.enum_consts.Count; i++) if (string.Compare(enum_consts[i], this.enum_consts[i], true) != 0) return false; return true; }
PVS-Studio warning: V3038 The 'enum_consts[i]' argument was passed to 'Compare' method several times. It is possible that other argument should be passed instead. CodeCompletion SymTable.cs 2206
I'll give some explanation here. The error in the factual arguments of the Compare function:
string.Compare(enum_consts[i], this.enum_consts[i], true)
The thing is that enum_consts[i] and this.enum_consts[i are the same things. As I understand, a correct call should be like this:
string.Compare(es.enum_consts[i], this.enum_consts[i], true)
or
string.Compare(enum_consts[i], es.enum_consts[i], true)
Quite a common error in programming is when the same check is done twice. Example:
return A == B && C == D && // <= C == D && // <= E == F;
Two variants are possible in this case. The first is quite harmless: one comparison is redundant and can be simply removed. The second is worse: some other variables were to be compared, but a programmer made a typo.
In any case, such code deserves close attention. Let me scare you a little more, and show that this error can be found even in the code of GCC compiler (C):
static bool dw_val_equal_p (dw_val_node *a, dw_val_node *b) { .... case dw_val_class_vms_delta: return (!strcmp (a->v.val_vms_delta.lbl1, b->v.val_vms_delta.lbl1)&& !strcmp (a->v.val_vms_delta.lbl1, b->v.val_vms_delta.lbl1)); .... }
PVS-Studio warning: V501 There are identical sub-expressions '!strcmp(a->v.val_vms_delta.lbl1, b->v.val_vms_delta.lbl1)' to the left and to the right of the '&&' operator. dwarf2out.c 1428
The function strcmp is called twice with the same set of arguments.
The code of Unreal Engine 4 project (C++):
FORCEINLINE bool operator==(const FShapedGlyphEntryKey& Other) const { return FontFace == Other.FontFace&& GlyphIndex == Other.GlyphIndex // <=&& FontSize == Other.FontSize&& FontScale == Other.FontScale&& GlyphIndex == Other.GlyphIndex; // <= }
PVS-Studio warning: V501 There are identical sub-expressions 'GlyphIndex == Other.GlyphIndex' to the left and to the right of the '&&' operator. fontcache.h 139
The code of Serious Engine project (C++):
inline BOOL CValuesForPrimitive::operator==(....) { return ( (....) && (vfp_ptPrimitiveType == vfpToCompare.vfp_ptPrimitiveType) && .... (vfp_ptPrimitiveType == vfpToCompare.vfp_ptPrimitiveType) && .... );
PVS-Studio warning: V501 There are identical sub-expressions '(vfp_ptPrimitiveType == vfpToCompare.vfp_ptPrimitiveType)' to the left and to the right of the '&&' operator. worldeditor.h 580
The code of Oracle VM Virtual Box project (C++):
typedef struct SCMDIFFSTATE { .... bool fIgnoreTrailingWhite; bool fIgnoreLeadingWhite; .... } SCMDIFFSTATE; /* Pointer to a diff state. */ typedef SCMDIFFSTATE *PSCMDIFFSTATE; /* Compare two lines */ DECLINLINE(bool) scmDiffCompare(PSCMDIFFSTATE pState, ....) { .... if (pState->fIgnoreTrailingWhite // <= || pState->fIgnoreTrailingWhite) // <= return scmDiffCompareSlow(....); .... }
PVS-Studio warning: V501 There are identical sub-expressions 'pState->fIgnoreTrailingWhite' to the left and to the right of the '||' operator. scmdiff.cpp 238
The memcmp function returns the following values of int type:
Please note that '>0' can be any number, not only 1. These numbers can be: 2, 3, 100, 256, 1024, 5555, 65536 and so on. This means that this result cannot be placed to a variable of the char and short type. The high bits can be lost, which might violate the logic of program execution.
Also this means that the result cannot be compared with constants 1 or -1. In other words, it is wrong to write this:
if (memcmp(a, b, sizeof(T)) == 1) if (memcmp(x, y, sizeof(T)) == -1)
Correct comparisons:
if (memcmp(a, b, sizeof(T)) > 0) if (memcmp(a, b, sizeof(T)) < 0)
The danger of this code is that it may successfully work for a long time. The errors may start showing up when moving to a new platform or with the change of the compiler version.
The code of ReactOS project (C++):
HRESULT WINAPI CRecycleBin::CompareIDs(....) { .... return MAKE_HRESULT(SEVERITY_SUCCESS, 0, (unsigned short)memcmp(pidl1->mkid.abID, pidl2->mkid.abID, pidl1->mkid.cb)); }
PVS-Studio warning: V642 Saving the 'memcmp' function result inside the 'unsigned short' type variable is inappropriate. The significant bits could be lost breaking the program's logic. recyclebin.cpp 542
The code of Firebird project (C++):
SSHORT TextType::compare(ULONG len1, const UCHAR* str1, ULONG len2, const UCHAR* str2) { .... SSHORT cmp = memcmp(str1, str2, MIN(len1, len2)); if (cmp == 0) cmp = (len1 < len2 ? -1 : (len1 > len2 ? 1 : 0)); return cmp; }
PVS-Studio warning: V642 Saving the 'memcmp' function result inside the 'short' type variable is inappropriate. The significant bits could be lost breaking the program's logic. texttype.cpp 338
The code of CoreCLR project (C++):
bool operator( )(const GUID& _Key1, const GUID& _Key2) const { return memcmp(&_Key1, &_Key2, sizeof(GUID)) == -1; }
PVS-Studio warning: V698 Expression 'memcmp(....) == -1' is incorrect. This function can return not only the value '-1', but any negative value. Consider using 'memcmp(....) < 0' instead. sos util.cpp 142
The code of OpenToonz project (C++):
bool TFilePath::operator<(const TFilePath &fp) const { .... char differ; differ = _wcsicmp(iName.c_str(), jName.c_str()); if (differ != 0) return differ < 0 ? true : false; .... }
PVS-Studio warning: V642 Saving the '_wcsicmp' function result inside the 'char' type variable is inappropriate. The significant bits could be lost, breaking the program's logic. tfilepath.cpp 328
This error pattern is typical for C# programs. Sometimes in the comparison functions programmers write the type casting with the help of the as operator. The error is that inadvertently a programmer verifies against null not the new reference, but the original one. Let's take a look at a synthetic example:
ChildT foo = obj as ChildT; if (obj == null) return false; if (foo.zzz()) {}
The check if (obj == null) protects from the situation, if the obj variable contains a null reference. However, there is no protection from the case if it turns out that the as operator returns a null reference. The correct code should be like this:
ChildT foo = obj as ChildT; if (foo == null) return false; if (foo.zzz()) {}
Typically, this error occurs due to negligence of the programmer. Similar bugs are possible in the programs in C and C++, but I haven't found such a case in our error base.
The code of MonoDevelop project (C#):
public override bool Equals (object o) { SolutionItemReference sr = o as SolutionItemReference; if (o == null) return false; return (path == sr.path) && (id == sr.id); }
PVS-Studio warning: V3019 Possibly an incorrect variable is compared to null after type conversion using 'as' keyword. Check variables 'o', 'sr'. MonoDevelop.Core SolutionItemReference.cs 81
The code of CoreFX (C#):
public override bool Equals(object comparand) { CredentialHostKey comparedCredentialKey = comparand as CredentialHostKey; if (comparand == null) { // This covers also the compared == null case return false; } bool equals = string.Equals(AuthenticationType, comparedCredentialKey.AuthenticationType, .... .... }
PVS-Studio warning: V3019 Possibly an incorrect variable is compared to null after type conversion using 'as' keyword. Check variables 'comparand', 'comparedCredentialKey'. CredentialCache.cs 4007
The code of Roslyn project (C#):
public override bool Equals(object obj) { var d = obj as DiagnosticDescription; if (obj == null) return false; if (!_code.Equals(d._code)) return false; .... }
PVS-Studio warning: V3019 Possibly an incorrect variable is compared to null after type conversion using 'as' keyword. Check variables 'obj', 'd'. DiagnosticDescription.cs 201
The code of Roslyn (C#):
protected override bool AreEqual(object other) { var otherResourceString = other as LocalizableResourceString; return other != null && _nameOfLocalizableResource == otherResourceString._nameOfLocalizableResource && _resourceManager == otherResourceString._resourceManager && _resourceSource == otherResourceString._resourceSource && .... }
PVS-Studio warning: V3019 Possibly an incorrect variable is compared to null after type conversion using 'as' keyword. Check variables 'other', 'otherResourceString'. LocalizableResourceString.cs 121
The code of MSBuild project (C#):
public override bool Equals(object obj) { AssemblyNameExtension name = obj as AssemblyNameExtension; if (obj == null) // <= { return false; } .... }
PVS-Studio warning: V3019 Possibly an incorrect variable is compared to null after type conversion using 'as' keyword. Check variables 'obj', 'name'. AssemblyRemapping.cs 64
The code of Mono project (C#):
public override bool Equals (object o) { UrlMembershipCondition umc = (o as UrlMembershipCondition); if (o == null) // <= return false; .... return (String.Compare (u, 0, umc.Url, ....) == 0); // <= }
PVS-Studio warning: V3019 Possibly an incorrect variable is compared to null after type conversion using 'as' keyword. Check variables 'o', 'umc'. UrlMembershipCondition.cs 111
The code of Media Portal 2 project (C#):
public override bool Equals(object obj) { EpisodeInfo other = obj as EpisodeInfo; if (obj == null) return false; if (TvdbId > 0 && other.TvdbId > 0) return TvdbId == other.TvdbId; .... }
PVS-Studio warning: V3019 Possibly an incorrect variable is compared to null after type conversion using 'as' keyword. Check variables 'obj', 'other'. EpisodeInfo.cs 560
The code of NASA World Wind project (C#):
public int CompareTo(object obj) { RenderableObject robj = obj as RenderableObject; if(obj == null) // <= return 1; return this.m_renderPriority.CompareTo(robj.RenderPriority); }
PVS-Studio warning: V3019 Possibly an incorrect variable is compared to null after type conversion using 'as' keyword. Check variables 'obj', 'robj'. RenderableObject.cs 199
In some functions, collections of items are compared. Of course, different variant of the loops are used for its comparison. If a programmer writes the code inattentively, it's easy to mix something up, as it is with the comparison functions. Let's look at a few of these situations.
The code of Trans-Proteomic Pipeline (C++):
bool Peptide::operator==(Peptide& p) { .... for (i = 0, j = 0; i < this->stripped.length(), j < p.stripped.length(); i++, j++) { .... }
PVS-Studio warning: V521 Such expressions using the ',' operator are dangerous. Make sure the expression is correct. tpplib peptide.cpp 191
Note that the comma operator is used in the condition. The code is clearly incorrect, because the condition, written to the left of the coma is ignored. That is, the condition on the left is evaluated, but its result is not used in any way.
The code of Qt project (C++):
bool equals( class1* val1, class2* val2 ) const { ... size_t size = val1->size(); ... while ( --size >= 0 ){ if ( !comp(*itr1,*itr2) ) return false; itr1++; itr2++; } ... }
PVS-Studio warning: V547 Expression '-- size >= 0' is always true. Unsigned type value is always >= 0. QtCLucene arrays.h 154
The code of CLucene project (C++):
class Arrays { .... bool equals( class1* val1, class2* val2 ) const{ static _comparator comp; if ( val1 == val2 ) return true; size_t size = val1->size(); if ( size != val2->size() ) return false; _itr1 itr1 = val1->begin(); _itr2 itr2 = val2->begin(); while ( --size >= 0 ){ if ( !comp(*itr1,*itr2) ) return false; itr1++; itr2++; } return true; } .... }
PVS-Studio warning: V547 Expression '-- size >= 0' is always true. Unsigned type value is always >= 0. arrays.h 154
The code of Mono project (C#):
public override bool Equals (object obj) { .... for (int i=0; i < list.Count; i++) { bool found = false; for (int j=0; i < ps.list.Count; j++) { // <= if (list [i].Equals (ps.list [j])) { found = true; break; } } if (!found) return false; } return true; }
PVS-Studio warning: V3015 It is likely that a wrong variable is being compared inside the 'for' operator. Consider reviewing 'i' corlib-net_4_x PermissionSet.cs 607
Apparently, there is a typo here, and the variable j instead of i should be used in the nested loop:
for (int j=0; j < ps.list.Count; j++)
Quite often in the comparison functions a programmer has to write code of this kind:
if (GetA().x == GetB().x && GetA().y == GetB().y)
Intermediate variables are used to reduce the size of the conditions or for optimization:
Type A = GetA(); Type B = GetB(); if (A.x == B.x && A.y == B.y)
But inadvertently, a person sometimes makes a mistake and initializes temporary variables with the same value:
Type A = GetA(); Type B = GetA();
Now let's take a look at these errors in the code of real applications.
The code of LibreOffice project (C++):
bool CmpAttr( const SfxPoolItem& rItem1, const SfxPoolItem& rItem2) { .... bool bNumOffsetEqual = false; ::boost::optional<sal_uInt16> oNumOffset1 = static_cast<const SwFmtPageDesc&>(rItem1).GetNumOffset(); ::boost::optional<sal_uInt16> oNumOffset2 = static_cast<const SwFmtPageDesc&>(rItem1).GetNumOffset(); if (!oNumOffset1 && !oNumOffset2) { bNumOffsetEqual = true; } else if (oNumOffset1 && oNumOffset2) { bNumOffsetEqual = oNumOffset1.get() == oNumOffset2.get(); } else { bNumOffsetEqual = false; } .... }
PVS-Studio warning: V656 Variables 'oNumOffset1', 'oNumOffset2' are initialized through the call to the same function. It's probably an error or un-optimized code. Check lines: 68, 69. findattr.cxx 69
The code of Qt project (C++):
AtomicComparator::ComparisonResult IntegerComparator::compare(const Item &o1, const AtomicComparator::Operator, const Item &o2) const { const Numeric *const num1 = o1.as<Numeric>(); const Numeric *const num2 = o1.as<Numeric>(); if(num1->isSigned() || num2->isSigned()) .... }
PVS-Studio warning: V656 Variables 'num1', 'num2' are initialized through the call to the same function. It's probably an error or un-optimized code. Consider inspecting the 'o1.as < Numeric > ()' expression. Check lines: 220, 221. qatomiccomparators.cpp 221
A large amount of errors, cited previously can be called the consequences of sloppy Copy-Paste. They fell under some categories of the erroneous pattern and I decided that it would be logical to describe them in corresponding sections. However, I have several errors that have clearly appeared because of sloppy code copying, but I have no idea how to classify them. That's why I collected these errors here.
The code of CoreCLR project (C++):
int __cdecl Compiler::RefCntCmp(const void* op1, const void* op2) { .... if (weight1) { .... if (varTypeIsGC(dsc1->TypeGet())) { weight1 += BB_UNITY_WEIGHT / 2; } if (dsc1->lvRegister) { weight1 += BB_UNITY_WEIGHT / 2; } } if (weight1) { .... if (varTypeIsGC(dsc2->TypeGet())) { weight1 += BB_UNITY_WEIGHT / 2; // <= } if (dsc2->lvRegister) { weight2 += BB_UNITY_WEIGHT / 2; } } .... }
PVS-Studio warning: V778 Two similar code fragments were found. Perhaps, this is a typo and 'weight2' variable should be used instead of 'weight1'. clrjit lclvars.cpp 2702
The function was long that's why it is shortened for the article. If we examine the code of the function, we'll see that a part of the code was copied, but in one fragment a programmer forgot to replace the variable weight1 with weight2.
The code of WPF samples by Microsoft project (C#):
public int Compare(GlyphRun a, GlyphRun b) { .... if (aPoint.Y > bPoint.Y) // <= { return -1; } else if (aPoint.Y > bPoint.Y) // <= { result = 1; } else if (aPoint.X < bPoint.X) { result = -1; } else if (aPoint.X > bPoint.X) { result = 1; } .... }
PVS-Studio warning: V3003 The use of 'if (A) {...} else if (A) {...}' pattern was detected. There is a probability of logical error presence. Check lines: 418, 422. txtserializerwriter.cs 418
The code of PascalABC.NET project (C#):
public void CompareInternal(....) { .... else if (left is int64_const) CompareInternal(left as int64_const, right as int64_const); .... else if (left is int64_const) CompareInternal(left as int64_const, right as int64_const); .... }
PVS-Studio warning: V3003 The use of 'if (A) {...} else if (A) {...}' pattern was detected. There is a probability of logical error presence. Check lines: 597, 631. ParserTools SyntaxTreeComparer.cs 597
The code of SharpDevelop project (C#):
public int Compare(SharpTreeNode x, SharpTreeNode y) { .... if (typeNameComparison == 0) { if (x.Text.ToString().Length < y.Text.ToString().Length) return -1; if (x.Text.ToString().Length < y.Text.ToString().Length) return 1; } .... }
PVS-Studio warning: V3021 There are two 'if' statements with identical conditional expressions. The first 'if' statement contains method return. This means that the second 'if' statement is senseless NamespaceTreeNode.cs 87
The code of Coin3D (C++):
int SbProfilingData::operator == (const SbProfilingData & rhs) const { if (this->actionType != rhs.actionType) return FALSE; if (this->actionStartTime != rhs.actionStopTime) return FALSE; if (this->actionStartTime != rhs.actionStopTime) return FALSE; .... }
PVS-Studio warning: V649 There are two 'if' statements with identical conditional expressions. The first 'if' statement contains function return. This means that the second 'if' statement is senseless. Check lines: 1205, 1206. sbprofilingdata.cpp 1206
The code of Spring (C++):
bool operator < (const aiFloatKey& o) const {return mTime < o.mTime;} bool operator > (const aiFloatKey& o) const {return mTime < o.mTime;}
PVS-Studio warning: V524 It is odd that the body of '>' function is fully equivalent to the body of '<' function. assimp 3dshelper.h 470
And here is the last, particularly interesting code fragment that PVS-Studio analyzer found in MySQL project (C++).
static int rr_cmp(uchar *a,uchar *b) { if (a[0] != b[0]) return (int) a[0] - (int) b[0]; if (a[1] != b[1]) return (int) a[1] - (int) b[1]; if (a[2] != b[2]) return (int) a[2] - (int) b[2]; if (a[3] != b[3]) return (int) a[3] - (int) b[3]; if (a[4] != b[4]) return (int) a[4] - (int) b[4]; if (a[5] != b[5]) return (int) a[1] - (int) b[5]; // <= if (a[6] != b[6]) return (int) a[6] - (int) b[6]; return (int) a[7] - (int) b[7]; }
PVS-Studio warning: V525 The code containing the collection of similar blocks. Check items '0', '1', '2', '3', '4', '1', '6' in lines 680, 682, 684, 689, 691, 693, 695. sql records.cc 680
Most likely, a programmer wrote the first comparison, then the second and got bored. So he copied to the buffer a text block:
if (a[1] != b[1]) return (int) a[1] - (int) b[1];
A pasted it to the text of the program as many times as he needed. Then he changed indexes, but made a mistake in one place and got an incorrect comparison:
if (a[5] != b[5]) return (int) a[1] - (int) b[5];
Note. I discuss this error in more detail in my mini-book "The Ultimate Question of Programming, Refactoring, and Everything" (see a chapter "Don't do the compiler's job").
In C# the accepted practice is to implement the Equals methods in such a way, so that they correctly process a situation, if a null reference is passed as an argument. Unfortunately, not all the methods are implemented according to this rule.
The code of GitExtensions (C#):
public override bool Equals(object obj) { return GetHashCode() == obj.GetHashCode(); // <= }
PVS-Studio warning: V3115 Passing 'null' to 'Equals(object obj)' method should not result in 'NullReferenceException'. Git.hub Organization.cs 14
The code of PascalABC.NET project (C#):
public override bool Equals(object obj) { var rhs = obj as ServiceReferenceMapFile; return FileName == rhs.FileName; }
PVS-Studio warning: V3115 Passing 'null' to 'Equals' method should not result in 'NullReferenceException'. ICSharpCode.SharpDevelop ServiceReferenceMapFile.cs 31
The code of G3D Content Pak project (C++):
bool Matrix4::operator==(const Matrix4& other) const { if (memcmp(this, &other, sizeof(Matrix4) == 0)) { return true; } ... }
PVS-Studio warning: V575 The 'memcmp' function processes '0' elements. Inspect the 'third' argument. graphics3D matrix4.cpp 269
One closing bracket is put incorrectly. As a result, the amount of bites compared is evaluated by the statement sizeof(Matrix4) == 0. The size of any class is more than 0, which means that the result of the expression is 0. Thus, 0 bites get compared.
Correct variant:
if (memcmp(this, &other, sizeof(Matrix4)) == 0) {
The code of Wolfenstein 3D project (C++):
inline int operator!=( quat_t a, quat_t b ) { return ( ( a.x != b.x ) || ( a.y != b.y ) || ( a.z != b.z ) && ( a.w != b.w ) ); }
PVS-Studio warning: V648 Priority of the '&&' operation is higher than that of the '||' operation. math_quaternion.h 167
Apparently, in one fragment the && operator was accidentally written instead of ||.
The code of FlightGear project (C):
static int tokMatch(struct Token* a, struct Token* b) { int i, l = a->strlen; if(!a || !b) return 0; .... }
PVS-Studio warning: V595 The 'a' pointer was utilized before it was verified against nullptr. Check lines: 478, 479. codegen.c 478
If we pass NULL as the first argument to the function, we'll get null pointer dereference, although the programmer wanted the function to return 0.
The code of WinMerge project (C++):
int TimeSizeCompare::CompareFiles(int compMethod, const DIFFITEM &di) { UINT code = DIFFCODE::SAME; ... if (di.left.size != di.right.size) { code &= ~DIFFCODE::SAME; code = DIFFCODE::DIFF; } ... }
PVS-Studio warning: V519 The 'code' variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 79, 80. Merge timesizecompare.cpp 80
The code of ReactOS project (C++):
#define IsEqualGUID(rguid1, rguid2) \ (!memcmp(&(rguid1), &(rguid2), sizeof(GUID))) static int ctl2_find_guid(....) { MSFT_GuidEntry *guidentry; ... if (IsEqualGUID(guidentry, guid)) return offset; ... }
PVS-Studio warning: V512 A call of the 'memcmp' function will lead to underflow of the buffer 'guidentry'. oleaut32 typelib2.c 320
A pointer is written here as the first argument. As a result, the address of the pointer gets evaluated, which has no sense.
Correct variant:
if (IsEqualGUID(*guidentry, guid)) return offset;
The code of IronPython and IronRuby project (C#):
public static bool Equals(float x, float y) { if (x == y) { return !Single.IsNaN(x); } return x == y; }
PVS-Studio warning: V3024 An odd precise comparison: x == y. Consider using a comparison with defined precision: Math.Abs(A - B) < Epsilon. FloatOps.cs 1048
It's not clear what is the point of a special check against NaN here. If the condition (x == y) is true, it means that both x and y and different from NaN, because NaN isn't equal to any other value, including itself. It seems that the check against NaN is just not necessary, and the code can be shortened to:
public static bool Equals(float x, float y) { return x == y; }
The code of Mono project (C#):
public bool Equals (CounterSample other) { return rawValue == other.rawValue && baseValue == other.counterFrequency && // <= counterFrequency == other.counterFrequency && // <= systemFrequency == other.systemFrequency && timeStamp == other.timeStamp && timeStamp100nSec == other.timeStamp100nSec && counterTimeStamp == other.counterTimeStamp && counterType == other.counterType; }
PVS-Studio warning: V3112 An abnormality within similar comparisons. It is possible that a typo is present inside the expression 'baseValue == other.counterFrequency'. System-net_4_x CounterSample.cs 139
Looking through all the errors, it seems miraculous that all these programs generally work. Indeed, the comparison functions do a very important and responsible task in program.
There are several explanations of why these programs work despite these errors:
I demonstrated how many errors can be found in the comparison functions. It follows that the efficiency of these functions should be checked with unit-tests by all means.
It is really necessary to write unit-tests for the comparison operators, for Equals functions and so on.
I am quite sure that there was such an understanding among programmers before reading this article, that unit tests for such functions is extra work and they won't detect any errors anyway: the comparison functions are just so simple at the first glance... Well, now I showed the horror that can hide in them.
Code reviews and using static analysis tools would also be a great help.
In this article we mentioned a large amount of big-name projects that are developed by highly qualified experts. These projects are thoroughly tested using different methodologies. Still, it didn't stop PVS-Studio from finding errors in them. This shows that PVS-Studio can become a nice complement to other methodologies used to improve the quality and reliability of the code.
This article demonstrates to new users how to install Ubuntu* Core on an Intel® IoT Gateway GB-BXTB-3825. The GB-BXTB-3825 is powered by an Intel® Atom™ E3825 dual-core processor which would be ideal for industrial applications such as data generation, data aggregation, and data analysis. Ubuntu* Core is a lightweight, transactional version of Ubuntu* designed for deployments on IoT devices. Snaps are universal Linux packages that are available to install on Ubuntu* Core to work on IoT devices and more. More information on the Gateway GB-BXTB-3825 is available at http://b2b.gigabyte.com/Embedded-System/GB-BXBT-3825-rev-10#ov. You can get detailed information on the Ubuntu* Core at https://www.ubuntu.com/core.
The hardware components used in this project are listed below:
The software requirements used in this project are listed below:
The first step is to create an Ubuntu SSO account from https://login.ubuntu.com. The account is required to create the first user on an Ubuntu Core installation.
Use an existing Linux system to generate the RSA key by running ssh-keygen-trsa on the Linux shell:
Figure 1: Generate an SSH key on the Linux shell
Your public key is now available as .ssh/id_rsa.pub in your home folder /home/Ubuntu/.ssh/id_rsa.pub.
Figure 2: Submitted the SSH keys successfully
The Gateway should have its BIOS updated to the latest version. To check your Gateway BIOS version:
Visit http://www.intel.com/content/www/us/en/support/boards-and-kits/000005850.html to download the latest BIOS version and for instructions on how to install.
Create a Live USB Ubuntu* Flash Drive
Figure 3: Gateway GB-BXTB-3825
Figure 4: Select boot device
Figure 5: Try Ubuntu without installing
xzcat /media/ubuntu/<name of the second USB flash drive>/ubuntu-core-16-amd64.img.xz | sudo dd of=/dev/sda bs=32M status=progress; sync
Figure 6: Flash Ubuntu Core
Figure 7: Configure IPv4
Figure 8: After network configuration
Figure 9: Profile setup
Figure 10: Configuration complete
Figure 11: ssh-add command
Figure 12: ssh into Ubuntu Core
Figure 13: Set a password
Now the Gateway is ready for the snaps. Snaps are self-contained application bundles that contain most of the libraries and runtimes needed. It is a squashFS filesystem containing your app code and a snap.yaml file.
Figure 15: Install hello snap
Figure 16: Run hello snap
We have described how to install Ubuntu* Core on an Intel IoT Gateway GB-BXTB-3825 and also how to run the Hello World Snap. Visit https://snapcraft.io/docs/build-snaps to make your own snap and enjoy the power of the Intel® IoT Gateway GB-BXTB-3825.
https://software.intel.com/en-us/iot/home
http://b2b.gigabyte.com/Embedded-System/GB-BXBT-3825-rev-10#ov
https://help.ubuntu.com/community/SSH/OpenSSH/Keys
https://www.ubuntu.com/core
https://help.ubuntu.com/community/SSH/OpenSSH/Keys
https://www.ubuntu.com/download/desktop/create-a-usb-stick-on-windows
https://rufus.akeo.ie
https://developer.ubuntu.com/core/get-started/intel-nuc
https://snapcraft.io/docs/build-snaps
Nancy Le is a software engineer at Intel Corporation in the Software and Services Group working on Intel Atom® processor enabling for Intel® IoT projects.
The Internet of Things is growing exponentially and shows no signs of stopping. We’ve all heard the statistics. By 2020, there will be billions of connected devices. And these devices are generating explosive volumes of data. The good news is that IoT devices are transforming the way we do business and helping to create a safer, more efficient, more innovative future. The bad news? If all that data has to be transported to the cloud for processing and analyzing, networks will be massively overwhelmed — leading us to a world of delayed results.
But not bad news for long. Smart, connected “things” are getting smarter. And a more intelligent edge is becoming capable of doing more complex analytics. In fact, IDC predicts “by 2019, at least 40 percent of IoT-created data will be stored, processed, analyzed, and acted upon close to or at the edge of the network associated drivers.”1
Think of a factory using smart devices to monitor the work environment and send notifications if conditions reach unsafe levels. The devices can sense the issue and process the data—enabling time-critical alerts so workers can be evacuated safely. Think of an oil or mining company using sensors and edge computing to monitor conditions and control heavy equipment to automate and optimize operations in remote locations. These are just two examples of how an IoT system with more compute power at the edge can speed the movement of data from insight to action.
Intel is driving smarter devices and a more intelligent edge with cloud and edge technologies that drive greater business value, edge analytics, deep learning and machine learning capabilities.
To further these efforts, we have created a joint reference architecture with Amazon Web Services (AWS)* and are launching an Enterprise IoT Developer Kit. The architecture incorporates AWS Greengrass software, which works seamlessly with the Intel® IoT Platform. With Greengrass, Intel® devices can ingest, process, and store data locally and make local decisions, paired with leading cloud-based capabilities.
The developer kit provides integration of sensors and the middleware protocol stack, shortening time-to-market from prototyping to deployment. The kit includes: Intel® IoT Gateway Technology, AWS* IoT and Greengrass-specific plugins, development boards and starter kits, IDEs to support a variety of programming languages, libraries to support I/O and sensor interactions, documentation, and code samples.
Intel has been implementing the reference architecture across their ecosystem, working with IoT Equipment Builders for validation and testing to ensure compatibility. There are already a number of Intel-based IoT Gateways validated for Greengrass, provided by leading IoT Equipment Builders, who are members of the IoT Solutions Alliance. With the backing of an extended IoT community, these and other IoT solutions are driving real-time insights to help businesses increase revenue, cut costs, and improve business outcomes.
Smarter things that are part of a more intelligent edge will fuel the growth of the IoT and its capability to bring meaning to data and benefits to business. To learn more, visit intel.com/iot/aws.
1IDC FutureScape: Worldwide Internet of Things 2017 Predictions, November 2016.
The updated version contains a new bug fix when compared to the previous Intel® Threading Building Blocks (Intel® TBB) 2017 Update 6 release. Information about new features of previous release you can find under the following link.
Intel TBB 2017 Update 7 is open source only release, you can download it from https://github.com/01org/tbb/releases.
We’re pleased to announce a new version of the Vectorization Assistant tool: Intel® Advisor 2017 Update 4. For details about download, terms and conditions, please refer to the Intel® Parallel Studio 2017 program site.
Below are highlights of the new functionality in Intel® Advisor 2017 Update 4:
Bug fixes
Visit the product site, where you can find videos and tutorials. Register for Intel® Parallel Studio XE 2017 to download the whole bundle, including Intel® Advisor 2017 update 4.
With an increasing number of workloads running simultaneously on a system, there is more pressure on shared resources such as the CPU, cache, network bandwidth, and memory. While this reduces workload performance, if one or more of the workloads is bursty in nature it also reduces performance determinism. An interfering workload is called a noisy neighbor, and for the purposes of this discussion a workload could be any software application, a container, or even a virtual machine (VM).
Intel® Resource Director Technology (Intel® RDT) provides hardware support to monitor and manage shared resources, such as the last level cache (LLC) (also called the L3 cache), and memory bandwidth. In conjunction with software support, starting with the operating system and going up the solution stack, this functionality is being made available to monitor and manage shared resources to isolate workloads and improve determinism. In particular, the cache monitoring technology (CMT) aspect of Intel RDT provides last-level cache usage information for a workload.
OpenStack* is an open source cloud operating system that controls datacenter resources, namely compute, storage, and networking. Users and administrators can access the resources through a web interface or RESTful API calls. For the purposes of this document, we assume that the reader has some knowledge of OpenStack, either as an operator/deployer, or as a developer.
Let us explore how to enable and use CMT, in the context of an OpenStack cloud, to detect cache-related workload interference and take remedial action(s).
Note 1: Readers of this article should have basic understanding of OpenStack and its deployment and configuration.
Note 2: All of the configurations and examples are based on the OpenStack Newton* release version (released in October 2016) and the Gnocchi* v3.0 release.
To leverage CMT in OpenStack requires touching the Nova*, Ceilometer*, and optionally the Gnocchi and Aodh* projects. The Nova project concerns itself with scheduling and managing workloads on the compute hosts. Ceilometer and Gnocchi pertain to telemetry. The Ceilometer agent runs on the compute hosts, gathers configured items of telemetry, and pushes them out for storage and future retrieval. The actual telemetry data could be saved in Ceilometer’s own database or the Gnocchi time series database with indices. The latter is superior, in both storage efficiency and retrieval speed. OpenStack Aodh supports defining rule-action pairs, such as whether some telemetry crosses a threshold and, if so, whether to emit an alarm. Alarms in turn could trigger some kind of operator intervention.
OpenStack Nova provides access to the compute resources via a RESTful API and a web dashboard. To enable the CMT feature in Nova, the following preconditions have to be met:
If all of the above preconditions are satisfied, and Nova is currently running, edit the libvirt section of the Nova configuration file (by default it is /etc/nova/nova.conf):
[libvirt] virt_type = kvm enabled_perf_events = cmt
After saving the above modifications, restart the Nova compute service.;
Openstack-nova-compute is a service on each compute host.
On Ubuntu* and CentOS* 6.5 hosts, run the following commands to restart the Nova compute service:
# service openstack-nova-compute restart
# service openstack-nova-compute status
On CentOS 7 and Fedora* 20 hosts, run the following commands instead to restart the Nova compute service:
# systemctl restart openstack-nova-compute
# systemctl status openstack-nova-compute
Once Nova is restarted, any new VMs launched by Nova will have the CMT feature enabled.
If devstack is being used instead to install a fresh OpenStack environment, add the following to the devstack local.conf file:
[[post-config|$NOVA_CONF]] [libvirt] virt_type = kvm enabled_perf_events = cmt, mbml, mbmt
After saving the above configuration, run devstack to start the installation.
Ceilometer is part of the OpenStack Telemetry project whose mission is to:
To get the last-level cache usage of a running VM, Ceilometer must be installed, configured to collect the cpu_l3_cache metric, and be running. Ceilometer defaults to collecting the metric. The cpu_l3_cache metric is collected by the Ceilometer agent running on the compute host by periodically polling for VM utilization metrics on the host.
If devstack is being used to install Ceilometer along with other OpenStack services and components, add the following in the devstack local.conf file:
[[local|localrc]] enable_plugin ceilometer git://git.openstack.org/openstack/ceilometer enable_plugin aodh git://git.openstack.org/openstack/aodh
After saving the above configuration, run devstack to start the installation. This will install Ceilometer as well as Aodh (OpenStack alarming service) in addition to other OpenStack services and components.
There are two options to save telemetry data; namely in Ceilometer’s own backend database or in Gnocchi’s (also a member of the OpenStack Telemetry project) database. Gnocchi provides a time-series database with a resource indexing service, which is vastly superior to the Ceilometer native storage with respect to performance at scale, better disk utilization, and faster data retrieval. We recommend installing Gnocchi and configuring storage with the same. To do so using devstack, modify the following devstack local.conf file as follows:
[[local|localrc]] enable_plugin ceilometer git://git.openstack.org/openstack/ceilometer CEILOMETER_BACKEND=gnocchi enable_plugin aodh git://git.openstack.org/openstack/aodh enable_plugin gnocchi git://git.openstack.org/openstack/gnocchi
After saving the above configuration, run devstack to start the installation.
Refer to Gnocchi documentation for information on other Gnocchi installation methods.
After installing Gnocchi and Ceilometer, confirm that the following configuration settings are in place:
In the Ceilometer configuration file (by default it is /etc/ceilometer/ceilometer.conf), make sure the options are listed as follows:
[DEFAULT] meter_dispatchers = gnocchi [dispatcher_gnocchi] filter_service_activity = False archive_policy = low url = <url to the Gnocchi API endpoint>
In the Gnocchi dispatcher configuration file (by default it is /etc/ceilometer/gnocchi_resources.yaml), make sure that the cpu_l3_cache metric is added into the resource type instance’s metrics list:
… … - resource_type: instance metrics: - 'instance' - 'memory' - 'memory.usage' - 'memory.resident' - 'vcpus' - 'cpu' - 'cpu_l3_cache' … …
If any modifications are made to the above configuration files, you must restart the Ceilometer collector so that the new configurations take effect.
To verify that all of the above are working, test as follows:
$ openstack server create --flavor m1.tiny --image cirros-0.3.4-x86_64-uec abc
$ openstack server list
ID | Name | Status | Networks | Image Name |
---|---|---|---|---|
7e38a89b-c829-4fb9-b44a-35090fbc0866 | abc | ACTIVE | private=10.0.0.3 | cirros-0.3.4-x86_64-uec |
ID | Resource ID | Name | Type | Volume | Unit | Timestamp |
---|---|---|---|---|---|---|
f42e275a-b36a-11e6-96b2-525400e9f0eb | 7e38a89b-c829-4fb9-b44a-35090fbc0866 | cpu_l3_cache | gauge | 270336.0 | B | 2016-12-08T23:57:37.535615 |
8e872286-b369-11e6-96b2-525400e9f0eb | 7e38a89b-c829-4fb9-b44a-35090fbc0866 | cpu_l3_cache | gauge | 450560.0 | B | 2016-12-08T23:47:37.505369 |
28e57758-b368-11e6-96b2-525400e9f0eb | 7e38a89b-c829-4fb9-b44a-35090fbc0866 | cpu_l3_cache | gauge | 270336.0 | B | 2016-12-08T23:37:37.536424 |
…... | …... | …... | …... | …... | …... | …... |
$ gnocchi measures show --resource-id 9184470a-594e-4a46-a124-fa3aaaf412dc cpu_l3_cache --aggregation mean
Timestamp | Granularity | Value |
---|---|---|
2016-12-09T00:00:00+00:00 | 86400.0 | 282350.933333 |
2016-12-09T01:00:00+00:00 | 3600.0 | 216268.8 |
2016-12-09T01:45:00+00:00 | 300.0 | 180224.0 |
2016-12-09T01:55:00+00:00 | 300.0 | 180224.0 |
… ... | … ... | … ... |
A noisy neighbor in the OpenStack environment could be a VM consuming resources in a manner that adversely affects one or more different VMs on the same compute node. Whether because of a lack of knowledge of workload characteristics, appropriate information during Nova scheduling, or a change in the workload characteristics (because of a spike in usage or a virus or other), a noisy situation may occur on a host. The cloud admin might want to detect and take some action, such as live migrating the greedy workload or terminating it. The OpenStack Aodh project) enables detecting scenarios and alerting to their existence using condition-action pairs. An Aodh rule that monitors VM cache usage crossing some threshold would automate detecting of noisy neighbor scenarios.
Below, we illustrate setting up an Aodh rule to detect noisy neighbors. The actual rule depends upon whether the CMT telemetry data is stored. We first cover storage in the Ceilometer database and then in the Gnocchi time series database.
Below, we define, using the Aodh command-line utility, a threshold CMT metrics rule:
$ aodh --debug alarm create --name cpu_l3_cache -t threshold --alarm-action "log://" --repeat-actions True --comparison-operator "gt" --threshold 180224 --meter-name cpu_l3_cache --period 600 --statistic avg
Field | Value |
---|---|
alarm_actions | [u'log://'] |
alarm_id | e3673d39-90ed-4455-80f1-fd7e06e1f2b8 |
comparison_operator | gt |
description | Alarm when cpu_l3_cache is gt a avg of 180224 over 600 seconds |
enabled | True |
evaluation_periods | 1 |
exclude_outliers | False |
insufficient_data_actions | [] |
meter_name | cpu_l3_cache |
name | cpu_l3_cache |
ok_actions | [] |
period | 600 |
project_id | f1730972dd484b94b3b943d93f3ee856 |
repeat_actions | True |
query |
|
severity | low |
state | insufficient data |
state_timestamp | 2016-12-08T23:59:05.712994 |
statistic | avg |
threshold | 180224 |
time_constraints | [] |
timestamp | 2016-12-08T23:59:05.712994 |
type | threshold |
user_id | cfcd1ea48a1046b192dbd3f5af11290e |
This creates an alarm rule named cpu_l3_cache that is triggered if, and only if, within a sliding window of 10 minutes (600 seconds), the VM’s average cpu_l3_cache metric is greater than 180224. If the alarm is triggered, it will be logged in the Aodh alarm notifier agent’s log. Alternately, instead of just logging the alarm event, a notifier may be used to push a notification to one or more configured endpoints. For example, we could use the http notifier by providing "http://<endpoint ip>:<endpoint port>" as the alarm-action parameter.
If the metrics are stored in Gnocchi, an Aodh alarm could be created through a gnocchi_resources_threshold rule such as the following, using the Aodh command-line utility:
$ aodh --debug alarm create -t gnocchi_resources_threshold --name test1 --alarm-action "log://alarm" --repeat-actions True --metric cpu_l3_cache --threshold 100000 --resource-id 9184470a-594e-4a46-a124-fa3aaaf412dc --aggregation-method mean --resource-type instance --granularity 300 --comparison-operator 'gt'
Field | Value |
---|---|
aggregation_method | mean |
alarm_actions | [u'log://alarm'] |
alarm_id | 71f48ee1-b92f-4982-92e4-4c520649a8e0 |
comparison_operator | gt |
description | gnocchi_resources_threshold alarm rule |
enabled | True |
evaluation_periods | 1 |
granularity | 300 |
insufficient_data_actions | [] |
metric | cpu_l3_cache |
name | test1 |
ok_actions | [] |
period | 600 |
project_id | 543aa2e8e17449149d5c101c55675005 |
repeat_actions | True |
resource_id | 9184470a-594e-4a46-a124-fa3aaaf412dc |
resource_type | instance |
state | insufficient data |
state_timestamp | 2016-12-09T05:57:07.089530 |
threshold | 100000 |
time_constraints | [] |
timestamp | 2016-12-09T05:57:07.089530 |
type | gnocchi_resources_threshold |
user_id | ca859810b379425085756faf6fd04ded |
This creates an alarm named test1 if, and only if, within a sliding 10-minute window (600 seconds), the VM 9184470a-594e-4a46-a124-fa3aaaf412dc registers an average cpu_l3_cache metric greater than 180224. If triggered, an alarm is logged to the Aodh alarm notifier agent’s log output. Instead of the command-line utility the Aodh RESTful API could be used to define alarms; refer to http://docs.openstack.org/developer/aodh/webapi/v2.html for details.
While Gnocchi v3.0 is limited in its resource querying capabilities in comprehending metric type and thresholds, such enhancements are expected in future releases.
The Intel RDT family comprises, beyond CMT, other monitoring and resource allocation technologies. Those that will soon be available are:
To learn more visit http://www.intel.com/content/www/us/en/architecture-and-technology/resource-director-technology.html.
In conclusion, we hope the above provides you with adequate information to start using CMT in an OpenStack cloud to gain deeper insights into workload characteristics to positively influence performance.
The Terasic DE-10 Nano is a development kit that contains a Cyclone* V device. The Cyclone V contains a Hard Processor System (HPS) and field-programmable gate array (FPGA) with a wealth of peripherals onboard for creating some interesting applications. One of the most basic things to accomplish with this system is to control the LEDs that are physically connected to the FPGA. This tutorial will discuss four different methods for controlling the LEDs using the command line, memory mapped IO, schematic, and Verilog HDL. Whether you are an application developer, firmware engineer, hardware engineer, or enthusiast, there is a method suited for you.
There are a wealth of datasheets, user guides, tools, and other information available for the DE-10 Nano. It is encouraged to review this documentation to get a deeper understanding of the system. For this tutorial, please download and install the following first:
01: Intel® Quartus® Prime Software Suite Lite Edition for Cyclone V - http://dl.altera.com/?edition=lite
02: Install EDS with DS-5 - http://dl.altera.com/soceds/
03: Install Putty (Windows* Users) - http://www.putty.org/
04: Install WinScp (Windows Users) - https://winscp.net/eng/download.php
05: Install the RNDIS Ethernet over USB driver (Windows Users) – See Terasic DE10 Nano Quick Start Guide Section 3
06: Download DE-10 Nano Resources - http://www.terasic.com.tw/cgi-bin/page/archive.pl?Language=English&CategoryNo=205&No=1046&PartNo=4
Out of the box, the DE-10 Nano HPS is pre-configured to boot a Linux* image and the FPGA is pre-configured with the Golden Hardware Reference Design (GHRD). This means you have a complete system and can get started exploring right away by simply applying power to the board. The most basic method to control an LED using the DE-10 Nano HPS is with the file system. This method lends itself well to the scripters out there that want to do something basic and work at the filesystem level. This can be easily illustrated using the serial terminal. To begin, perform the following:
01: Connect a Mini-B USB cable from the host to the DE10 Nano USB UART (Right Side of board)
02: Open a serial terminal program
03: Connect using a 115200 baud rate
04: Login as root, no password is needed
05: Turn on the LED
echo 1 > /sys/class/leds/fpga_led0/brightness
06: Turn off the LED
echo 0 > /sys/class/leds/fpga_led0/brightness
Another method to control the LEDs using the HPS, is to go lower level and develop a Linux application that accesses the memory mapped regions in SDRAM exposed by the FPGA that control the LEDs. The HPS can access this region using the Lightweight HPS2FPGA AXI Bridge (LWFPGASLAVES) that connects to the Parallel IO (LED_PIO) area. The C based application will map this region into the user application space, toggle all 8 LEDs every 500ms for a few times, unmap the region, and exit. We will develop the application using the Eclipse DS-5 IDE. To begin, perform the following:
01: Open Eclipse DS-5
02: Create a New Project
02a: File->New->C Project->Hello World Project
02b: Enter a project Name
02c: Select GCC 4.x [arm-linux-gnueabihf) Toolchain
02d: Click Finish
03: Delete the generated Hello World code
04: Add Preprocessor Includes & Defines
#include <stdio.h> #include <unistd.h> #include <fcntl.h> #include <sys/mman.h> #define ALT_LWFPGASLVS_OFST 0xFF200000 #define LED_PIO_BASE 0x3000 #define LED_PIO_SPAN 0x10
05: Add main() function
int main(void) { unsigned long *led_pio; int fd; int i; fd = open("/dev/mem", (O_RDWR | O_SYNC)); //Map LED_PIO Physical Address to Virtual Address Space led_pio = mmap( NULL, LED_PIO_SPAN, ( PROT_READ | PROT_WRITE ), MAP_SHARED, fd, (ALT_LWFPGASLVS_OFST + LED_PIO_BASE) ); //Toggle all LEDs every 500ms a few times for (i=0; i < 10; i++) { *led_pio ^= 0xFF; //Bit0=LED0 … Bit7=LED7 usleep(1000*500); } //Unmap munmap(led_pio, LED_PIO_SPAN); close(fd); return(0); }
06: Build the Project
Project->Build Project
07: Test out the application
06a: Connect a micro USB cable from the host to the DE10 Nano USB OTG Port
06b: Use scp to transfer the application to the DE10 Nano at root@192.168.7.1
06c: Run the application from the serial terminal ./<applicationName>
So far we have been controlling the LEDs connected to the FPGA from the HPS using the command line and a C based application. Now let’s discuss controlling the LEDs directly using just the FPGA logic. In this design, we will turn on/off 2 LEDs when a pushbutton is pressed/released respectively. It should be noted that the pushbutton is pulled up and the LEDs are active high so an inverter is used to get the desired behavior when the button is pressed/released. We will use a schematic based approach to create the logic to control the first LED and a Verilog HDL approach to create the similar logic to control the second LED. We will create the design using the Intel® Quartus® Prime Software Suite Lite Edition software. To begin the project, perform the following:
01: Open Quartus Prime Lite
02: Create a New Project
02a: File->New->New Quartus Prime Project->Next
02b: Enter Project Name->Next->Empty Project
02c: Click Next
02c: Name Filter->5CSEBA6U23I7->Finish
03: Create a New Schematic File
03a: File->New->Block Diagram/Schematic File
04: Add LED Output Pins
04a: Right Click->Insert Symbol->primitives->pin->output
04b: Right Click->Insert Symbol->primitives->pin->output
04c: Right Click on output pin->Properties->Name=led_0
04d: Right Click on output pin->Properties->Name=led_1
05: Add Push Button Input Pin
05a: Right Click->Insert Symbol->primitives->pin->input
05b: Right Click on input pin->Properties->Name=pushButton
06: Add Inverter
06a: Right Click->Insert Symbol->primitives->logic->not
07: Connect Everything Up
07a: Connect pushButton to Inverter Input
07b: Connect Inverter Output to led_0
08: Create a New Verilog HDL File
08a: File->New->Verilog HDL File
08b: Enter Verilog Code
module inverter ( input in, output out ); assign out = !in; endmodule
08c: Save File
08d: Update Symbols
File->Create/Update->Create Symbols From Current File
08e: Add Verilog Module to Top Level Schematic
Right Click->Insert Symbol->inverter->Click Ok
08f: Connect pushButton Input to Inverter Input
08g: Connect Inverter Output to led1 Output Pin
09: Assign Inputs and Outputs to Physical FPGA Pins
09a: Processing->Start->Start Analysis & Elaboration
09b: Assignments->Pin Planner
led0->Location=PIN_W15, I/O Standard=3.3-V LVTTL
led1->Location=PIN_AA24, I/O Standard=3.3-V LVTTL
pushButton->Location=PIN_AH17
10: Compile Project
10a: Start->Start Compilation
11: Program the FPGA
11a: Connect mini USB cable to JTAG USB Blaster port (near HDMI connector and Blue LED)
11b: Click Tools->Programmer
11c: Click Hardware Setup->Currently Selected Hardware->DE-SoC
11d: Click AutoDetect->5CSEBA6
11e: Click on 5CSEBA6U23 Chip Picture
11f: Click Change File-><project directory>\output_files\yourFile.sof
11g: Click Program/Configure checkbox
11h: Click Start Button
12: Test out the design
12a: Push and hold the right pushbutton and led0 and led1 will turn on
12b: Release the pushbutton and the LEDs will turn off
The DE-10 Nano has a lot to offer the engineer from its capabilities, variety of tools, programming methods, and documentation. This tutorial showed four different methods for controlling the LEDs that utilized the HPS and FPGA using the available tools. You can take all of these concepts to the next level when you begin your next project with the DE-10 Nano.
Mike Rylee is a Software Engineer at Intel Corporation with a background in developing embedded systems and apps for Android*, Windows*, iOS*, and Mac*. He currently works on Internet of Things projects.
No license (express or implied, by estoppel or otherwise) to any intellectual property rights is granted by this document.
Intel disclaims all express and implied warranties, including without limitation, the implied warranties of merchantability, fitness for a particular purpose, and non-infringement, as well as any warranty arising from course of performance, course of dealing, or usage in trade.
This document contains information on products, services and/or processes in development. All information provided here is subject to change without notice. Contact your Intel representative to obtain the latest forecast, schedule, specifications and roadmaps.
The products and services described may contain defects or errors known as errata which may cause deviations from published specifications. Current characterized errata are available on request.
Copies of documents which have an order number and are referenced in this document may be obtained by calling 1-800-548-4725 or by visiting www.intel.com/design/literature.htm.
Intel, the Intel logo, and Intel RealSense are trademarks of Intel Corporation in the U.S. and/or other countries.
*Other names and brands may be claimed as the property of others
**This sample source code is released under the Intel Sample Source Code License Agreement
© 2017 Intel Corporation.
Adler32 is a common checksum used for checking the integrity of data in applications such as zlib*, a popular compression library. It is designed to be fast to execute in software, but in this paper we present a method to compute it with significantly better performance than the previous implementations. We show how the vector processing capabilities of Intel® Architecture Processors can be exploited to efficiently compute the Adler32 checksum.
The Adler32 checksum (https://en.wikipedia.org/wiki/Adler-32) is similar to the Fletcher checksum, but it is designed to catch certain differences that Fletcher is not able to catch. It is used, among other places, in the zlib data compression library (https://en.wikipedia.org/wiki/Zlib), a popular general-purpose compression library.
While scalar implementations of Adler32 can achieve reasonable performance, this paper presents a way to further improve the performance by using the vector processing feature of Intel processors. This is an extension of the method we used to speed up the Fletcher checksum as described in (https://software.intel.com/en-us/articles/fast-computation-of-fletcher-checksums).
If the input stream is considered to be an array of bytes (data), the checksum essentially consists of two 16-bit words (A and B), and the checksum can be defined as:
for (i=0; i<end; i++) { A = (A + data[i]) % 65521; B = (B + A) % 65521; }
Doing the modulo operation after every addition is expensive. A well-known way to speed this up is to do the addition using larger variables (for example, 32-bit dwords), and then to perform the modulo only when the variables are about to risk overflowing, for example:
for (i=0; i<5552; i++) { A = (A + data[i]); B = (B + A); } A = A % 65521; B = B % 65521;
The reason that up to 5552 bytes can be processed before needing to do the modulo is that if A and B are initially 65520 and the data is all 0xFF (255), after processing 5552 bytes, B (the larger of the two) will be 0xFFFBC598. But if one processes 5553 such bytes, the result would be greater than 232.
Within that loop, the calculation looks the same as in Fletcher, so the same approach can be used to vectorize the calculation. In this case, the body of the main loop would be an unrolled version of:
pmovzxbd xdata0, [data] ; Loads byte data into dword lanes paddd xa, xdata0 paddd xb, xa
One can see that this looks essentially identical to what one would do with scalar code, except that it is operating on vector registers and, depending on the hardware generation, could be processing 4, 8, or 16 bytes in parallel.
If “a[i]” represents the i’th lane of vector register “a” and N is the number of lanes, we can (as shown in the earlier paper) calculate the actual sums by:
The sums can be done using a series of horizontal adds (PHADDD), and the scaling can be done with PMULLD.
In pseudo-code, if the main loop is operating on eight lanes (either with eight lanes in one register or four lanes unrolled by a factor of two), this might look like:
While (size != 0) { s = min(size, 5222) end = data + s – 7 while (data < end) { compute vector sum data += 8 } end += 7 if (0 == (s & 7)) { size -= s; reduce from vector to scalar sum compute modulo continue while loop } // process final 1…7 bytes Reduce from vector to scalar sum Do final adds in scalar loop Compute modulo }
The following graph compares the cycles as a function of input buffer size for an optimized scalar implementation, and for both a Streaming SIMD Extension and Intel® Advanced Vector Extensions 2 (Intel® AVX2) based parallel version, as described in this paper.
One can clearly see that the vector versions have a significantly better performance than an optimized scalar one. This is true for all but the smallest buffers.
An Intel® Advanced Vector Extensions 512 version was not tested, but it should perform significantly faster than the Intel AVX2 version.
Versions of this code are in the process of being integrated and released as part of the Intel® Intelligent Storage Acceleration Library (https://software.intel.com/en-us/storage/ISA-L).
This paper illustrated a method for improved Adler32 checksum performance. By leveraging architectural features such as SIMD in the processors and combining innovative software techniques, large performance gains are possible.
Jim Guilford is an architect in the Intel Data Center Group, specializing in software and hardware features relating to cryptography and compression.
Simplicity is the ultimate sophistication.
—Leonardo Da Vinci
With time, machine learning algorithms are becoming increasingly complex. This, in most cases, is increasing accuracy at the expense of higher training-time requirements. Fast-training algorithms that deliver decent accuracy are also available. These types of algorithms are generally based on simple mathematical concepts and principles. Today, we’ll have a look at a similar machine-learning classification algorithm, naive Bayes. It is an extremely simple, probabilistic classification algorithm which, astonishingly, achieves decent accuracy in many scenarios.
In machine learning, naive Bayes classifiers are simple, probabilistic classifiers that use Bayes’ Theorem. Naive Bayes has strong (naive), independence assumptions between features. In simple terms, a naive Bayes classifier assumes that the presence of a particular feature in a class is unrelated to the presence of any other feature. For example, a ball may be considered a soccer ball if it is hard, round, and about seven inches in diameter. Even if these features depend on each other or upon the existence of the other features, naive Bayes believes that all of these properties independently contribute to the probability that this ball is a soccer ball. This is why it is known as naive.
Naive Bayes models are easy to build. They are also very useful for very large datasets. Although, naive Bayes models are simple, they are known to outperform even the most highly sophisticated classification models. Because they also require a relatively short training time, they make a good alternative for use in classification problems.
Bayes Theorem provides a way of calculating posterior probability P(c|x) from P(c), P(x), and P(x|c). Consider the following equation:
Here,
Let’s better understand this with the help of a simple example. Consider a well-shuffled deck of playing cards. A card is picked from that deck at random. The objective is to find the probability of a King card, given that the card picked is red in color.
Here,
P(King | Red Card) = ?
We’ll use,
P(King | Red Card) = P(Red Card | King) x P(King) / P(Red Card)
So,
P (Red Card | King) = Probability of getting a Red card given that the card chosen is King = 2 Red Kings / 4 Total Kings = ½
P (King) = Probability that the chosen card is a King = 4 Kings / 52 Total Cards = 1 / 13
(Red Card) = Probability that the chosen card is red = 13 Red cards / 52 Total Cards = 1/ 4
Hence, finding the posterior probability of randomly choosing a King given a Red card is:
P (King | Red Card) = (1 / 2) x (1 / 13) / (1 / 4) = 2 / 13 or 0.153
Let’s understand naive Bayes with one more example—to predict the weather based on three predictors: humidity, temperature and wind speed. The training data is the following:
Humidity | Temperature | Wind Speed | Weather |
---|---|---|---|
Humid | Hot | Fast | Sunny |
Humid | Hot | Fast | Sunny |
Humid | Hot | Slow | Sunny |
Not Humid | Cold | Fast | Sunny |
Not Humid | Hot | Slow | Rainy |
Not Humid | Cold | Fast | Rainy |
Humid | Hot | Slow | Rainy |
Humid | Cold | Slow | Rainy |
We’ll use naive Bayes to predict the weather for the following test observation:
Humidity % | Temperature (C) | Wind Speed (Km/h) | Weather |
---|---|---|---|
Humid | Cold | Fast | ? |
We have to determine which posterior is greater, sunny or rainy. For the classification Sunny, the posterior is given by:
Posterior( Sunny) = (P(Sunny) x P(Humid / Sunny) x P(Cold / Sunny) x P(Fast / Sunny)) / evidence
Similarly, for the classification Rainy, the posterior is given by:
Posterior( Rainy) = (P(Rainy) x P(Humid / Rainy) x P(Cold / Rainy) x P(Fast / Rainy)) / evidence
Where,
evidence = [ P(Sunny) x p(Humid / Sunny) x p(Cold / Sunny) x P(Fast / Sunny) ] + [ (P(Rainy) x P(Humid / Rainy) x P(Cold / Rainy) x P(Fast / Rainy) ) ]
Here,
P(Sunny) = 0.5 P(Rainy) = 0.5 P(Humid/ Sunny) = 0.75 P(Cold/ Sunny) = 0.25 P(Fast/ Sunny) = 0.75 P(Humid/ Sunny) = 0.25 P(Cold/ Sunny) = 0.75 P(Fast/ Sunny) = 0.25
Therefore, evidence = 0.703 + 0.023 = 0.726.
Posterior (Sunny) = 0.968 Posterior (Rainy) = 0.032
Since the posterior numerator is greater in the Sunny case, we predict the sample is Sunny.
Naive Bayes classifiers can be trained very efficiently in a supervised learning setting. In many practical applications, parameter estimation for naive Bayes models uses the method of maximum likelihood. Despite their naive design and apparently oversimplified assumptions, naive Bayes classifiers have worked quite well in many complex real-world situations.
An interesting point about naive Bayes is that even when the independence assumption is violated and there are clear, known relationships between attributes, it works decently anyway. There are two reasons that make naive Bayes a very efficient algorithm for classification problems.
Let’s see a practical application of naive Bayes for classifying email as spam or ham. We will use sklearn.naive_bayes to train a spam classifier in Python*.
import os import os import io import numpy from pandas import DataFrame from sklearn.feature_extraction.text import CountVectorizer from sklearn.naive_bayes import MultinomialNB
The following example will be using the MultinomialNB operation.
Creating the readFiles function:
def readFiles(path): for root, dirnames, filenames in os.walk(path): for filename in filenames: path = os.path.join(root, filename) inBody = False lines = [] f = io.open(path, 'r', encoding='latin1') for line in f: if inBody: lines.append(line) elif line == '\n': inBody = True f.close() message = '\n'.join(lines) yield path, message
Creating a function to help us create a dataFrame:
def dataFrameFromDirectory(path, classification): rows = [] index = [] for filename, message in readFiles(path): rows.append({'message': message, 'class': classification}) index.append(filename) return DataFrame(rows, index=index) data = DataFrame({'message': [], 'class': []}) data = data.append(dataFrameFromDirectory('/…/SPAMORHAM /emails/spam/', 'spam')) data = data.append(dataFrameFromDirectory('/…/SPAMORHAM/emails/ham/', 'ham'))
Let's have a look at that dataFrame:
data.head()
class message
/…/SPAMORHAM/emails/spam/00001.7848dde101aa985090474a91ec93fcf0 spam <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Tr... /…/SPAMORHAM/emails/spam/00002.d94f1b97e48ed3b553b3508d116e6a09 spam 1) Fight The Risk of Cancer!\n\nhttp://www.adc... /…/SPAMORHAM/emails/spam/00003.2ee33bc6eacdb11f38d052c44819ba6c spam 1) Fight The Risk of Cancer!\n\nhttp://www.adc... /…/SPAMORHAM/emails/spam/00004.eac8de8d759b7e74154f142194282724 spam ##############################################... /…/SPAMORHAM/emails/spam/00005.57696a39d7d84318ce497886896bf90d spam I thought you might like these:\n\n1) Slim Dow...
Now we will use a CountVectorizer to split up each message into its list of words, and throw that into a MultinomialNB classifier. Call the fit() method:
vectorizer = CountVectorizer() counts = vectorizer.fit_transform(data['message'].values) counts
<3000x62964 sparse matrix of type '<type 'numpy.int64'>'
with 429785 stored elements in Compressed Sparse Row format>
Now we are using MultinomialNB():
classifierModel = MultinomialNB()
## This is the target
## Class is the target
targets = data['class'].values
## Using counts to fit the model
classifierModel.fit(counts, targets) MultinomialNB(alpha=1.0, class_prior=None, fit_prior=True)
The classifierModel is ready. Now, let’s prepare sample email messages to see how the model works.
Email number 1 is Free Viagra now!!!, Email number 2 is A quick brown fox is not ready, and so on:
examples = ['Free Viagra now!!!',"A quick brown fox is not ready","Could you bring me the black coffee as well?","Hi Bob, how about a game of golf tomorrow, are you FREE?","Dude , what are you saying","I am FREE now, you can come","FREE FREE FREE Sex, I am FREE","CENTRAL BANK OF NIGERIA has 100 Million for you","I am not available today, meet Sunday?"] example_counts = vectorizer.transform(examples)
Now we are using the classifierModel to predict:
predictions = classifierModel.predict(example_counts)
Let’s check the prediction for each email:
predictions
array(['spam', 'ham', 'ham', 'ham', 'ham', 'ham', 'spam', 'spam', 'ham'],
dtype='|S4')
Therefore, the first email is spam, the second is ham, and so on.
We hope you have gained a clear understanding of the mathematical concepts and principles of naive Bayes using this guide. It is an extremely simple algorithm, with oversimplified assumptions at times, that might not stand true in many real-world scenarios. In this article we explained why naive Bayes often produces decent results, despite these facts. We feel naive Bayes is a very good algorithm and its performance, despite its simplicity, is astonishing.