intel_mkl_tool/
config.rs

1use anyhow::{bail, Result};
2use std::{fmt, str::FromStr};
3
4macro_rules! impl_otherwise {
5    ($e:ident, $a:ident, $b:ident) => {
6        impl $e {
7            pub fn otherwise(&self) -> Self {
8                match self {
9                    $e::$a => $e::$b,
10                    $e::$b => $e::$a,
11                }
12            }
13        }
14    };
15}
16
17pub const VALID_CONFIGS: &[&str] = &[
18    "mkl-dynamic-ilp64-iomp",
19    "mkl-dynamic-ilp64-seq",
20    "mkl-dynamic-lp64-iomp",
21    "mkl-dynamic-lp64-seq",
22    "mkl-static-ilp64-iomp",
23    "mkl-static-ilp64-seq",
24    "mkl-static-lp64-iomp",
25    "mkl-static-lp64-seq",
26];
27
28/// How to link MKL
29#[derive(Debug, Clone, Copy, PartialEq, Eq)]
30pub enum LinkType {
31    Static,
32    Dynamic,
33}
34impl_otherwise!(LinkType, Static, Dynamic);
35
36impl fmt::Display for LinkType {
37    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
38        match self {
39            LinkType::Static => write!(f, "static"),
40            LinkType::Dynamic => write!(f, "dynamic"),
41        }
42    }
43}
44
45impl Default for LinkType {
46    fn default() -> Self {
47        LinkType::Static
48    }
49}
50
51impl FromStr for LinkType {
52    type Err = anyhow::Error;
53    fn from_str(input: &str) -> Result<Self> {
54        Ok(match input {
55            "static" => LinkType::Static,
56            "dynamic" => LinkType::Dynamic,
57            another => bail!("Invalid link spec: {}", another),
58        })
59    }
60}
61
62/// Data model of library
63///
64/// Array index of some APIs in MKL are defined by `int` in C,
65/// whose size is not fixed.
66#[derive(Debug, Clone, Copy, PartialEq, Eq)]
67pub enum DataModel {
68    /// `long` and pointer are 64bit, i.e. `sizeof(int) == 4`
69    LP64,
70    /// `int`, `long` and pointer are 64bit, i.e. `sizeof(int) == 8`
71    ILP64,
72}
73impl_otherwise!(DataModel, LP64, ILP64);
74
75impl fmt::Display for DataModel {
76    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
77        match self {
78            DataModel::LP64 => write!(f, "lp64"),
79            DataModel::ILP64 => write!(f, "ilp64"),
80        }
81    }
82}
83
84impl Default for DataModel {
85    fn default() -> Self {
86        DataModel::ILP64
87    }
88}
89
90impl FromStr for DataModel {
91    type Err = anyhow::Error;
92    fn from_str(input: &str) -> Result<Self> {
93        Ok(match input {
94            "lp64" => DataModel::LP64,
95            "ilp64" => DataModel::ILP64,
96            another => bail!("Invalid index spec: {}", another),
97        })
98    }
99}
100
101/// How to manage thread(s)
102#[derive(Debug, Clone, Copy, PartialEq, Eq)]
103pub enum Threading {
104    /// Use iomp5, Intel OpenMP runtime.
105    OpenMP,
106    /// No OpenMP runtime.
107    Sequential,
108}
109
110impl_otherwise!(Threading, OpenMP, Sequential);
111
112impl Default for Threading {
113    fn default() -> Self {
114        Threading::Sequential
115    }
116}
117
118impl fmt::Display for Threading {
119    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
120        match self {
121            Threading::OpenMP => write!(f, "iomp"),
122            Threading::Sequential => write!(f, "seq"),
123        }
124    }
125}
126
127impl FromStr for Threading {
128    type Err = anyhow::Error;
129    fn from_str(input: &str) -> Result<Self> {
130        Ok(match input {
131            "iomp" => Threading::OpenMP,
132            "seq" => Threading::Sequential,
133            another => bail!("Invalid parallel spec: {}", another),
134        })
135    }
136}
137
138/// Configuration for Intel MKL, e.g. `mkl-static-lp64-seq`
139///
140/// There are 2x2x2=8 combinations of [LinkType], [DataModel], and [Threading].
141#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
142pub struct Config {
143    pub link: LinkType,
144    pub index_size: DataModel,
145    pub parallel: Threading,
146}
147
148impl fmt::Display for Config {
149    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
150        write!(f, "mkl-{}-{}-{}", self.link, self.index_size, self.parallel)
151    }
152}
153
154impl FromStr for Config {
155    type Err = anyhow::Error;
156    fn from_str(name: &str) -> Result<Self> {
157        let parts: Vec<_> = name.split('-').collect();
158        if parts.len() != 4 {
159            bail!("Invalid name: {}", name);
160        }
161        if parts[0] != "mkl" {
162            bail!("Name must start with 'mkl': {}", name);
163        }
164        Ok(Config {
165            link: LinkType::from_str(parts[1])?,
166            index_size: DataModel::from_str(parts[2])?,
167            parallel: Threading::from_str(parts[3])?,
168        })
169    }
170}
171
172impl Config {
173    pub fn possibles() -> Vec<Self> {
174        VALID_CONFIGS
175            .iter()
176            .map(|name| Self::from_str(name).unwrap())
177            .collect()
178    }
179}
180
181#[cfg(test)]
182mod tests {
183    use super::*;
184
185    #[test]
186    fn name_to_config() -> Result<()> {
187        let cfg = Config::from_str("mkl-static-lp64-iomp")?;
188        assert_eq!(
189            cfg,
190            Config {
191                link: LinkType::Static,
192                index_size: DataModel::LP64,
193                parallel: Threading::OpenMP
194            }
195        );
196        Ok(())
197    }
198
199    #[test]
200    fn name_to_config_to_name() -> Result<()> {
201        for name in VALID_CONFIGS {
202            let cfg = Config::from_str(name)?;
203            assert_eq!(&cfg.to_string(), name);
204        }
205        Ok(())
206    }
207
208    #[test]
209    fn invalid_names() -> Result<()> {
210        assert!(Config::from_str("").is_err());
211        assert!(Config::from_str("static-lp64-iomp").is_err());
212        assert!(Config::from_str("mkll-static-lp64-iomp").is_err());
213        assert!(Config::from_str("mkl-sttic-lp64-iomp").is_err());
214        assert!(Config::from_str("mkl-static-l64-iomp").is_err());
215        assert!(Config::from_str("mkl-static-lp64-omp").is_err());
216        Ok(())
217    }
218}